<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=PICture</id>
		<title>RN-Wissen.de - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=PICture"/>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Spezial:Beitr%C3%A4ge/PICture"/>
		<updated>2026-04-11T14:47:13Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.25.1</generator>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=26092</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=26092"/>
				<updated>2015-01-26T12:39:25Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* 7-Segment mit 3 Backplanes ohne Kontroller */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. &lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Ein sogenannter Prozessortakt besteht aus 4 Oszillator-Takten, die jeweils einen Teil eines Befehls abarbeiten. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. In dieser Form wird auch von Assembler oder kurz ASM gesprochen. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie bis zu 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des großen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Anders als bei einer Hochsprache ist die &amp;quot;Übersetzung&amp;quot; genau vorhersehbar und festgelegt. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich. Bei PIC's ist echtes Multitasking (Parallellaufen) nur mit Timer und ADC Wandler möglich (siehe dazu: http://www.roboternetz.de/community/threads/42200-Frequenzz%C3%A4hler-mit-LPH2673-1-%28zum-Nachbauen%29?highlight=LPH2673-1 ) &lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende ausgeführt. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
        +&amp;lt;---------------------------------------+&lt;br /&gt;
        |                                        |&lt;br /&gt;
        V                                        |&lt;br /&gt;
        /\               /\               /\     |&lt;br /&gt;
       /  \             /  \             /  \    |&lt;br /&gt;
      /    \ J         /    \ J         /    \ J |&lt;br /&gt;
     /F1=0 ?\-&amp;gt;+- - -&amp;gt;/Fn=0 ?\-&amp;gt;+- - -&amp;gt;/F8=0 ?\-&amp;gt;+&lt;br /&gt;
     \      /  A      \      /  A      \      /  A&lt;br /&gt;
      \    /   |       \    /   |       \    /   |&lt;br /&gt;
       \  /    |        \  /    |        \  /    |&lt;br /&gt;
        \/     |         \/     |         \/     |&lt;br /&gt;
        |N     |         |N     |         |N     |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
     .------.  |      .------.  |      .------.  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     | TUN1 |  |      | TUNn |  |      | TUN8 |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     '------'  |      '------'  |      '------'  |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        +------+         +------+         +------+&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer (TMR) unterbrochen und nächster Tast gestartet. Dafür muss immer nach Beenden von jedem Task die Endadresse vom Programm Counter (PC), wo der Task unterbrochen wurde (EA1), auf dem Stapel als nächste Startadresse (AA1) gespeichert werden. Wenn die Zeit für den unterbrochenen Task wieder kommt, wird er ab der unterbrochenen Stelle (AA1) wieder in der ihn zustehenden Zeit ausgeführt, wieder unterbrochen, u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist. Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
        +--------------------------------------------------------+&lt;br /&gt;
        |  .-----.              .-----.              .-----.     |&lt;br /&gt;
        +-&amp;gt;|Task1|----&amp;gt;+- - - -&amp;gt;|Taskn|----&amp;gt;+- - - -&amp;gt;|Task8|----&amp;gt;+&lt;br /&gt;
           '-----'     |        '-----'     |        '-----'     |&lt;br /&gt;
              |        |           |        |           |        |&lt;br /&gt;
              V        |           V        |           V        |&lt;br /&gt;
             /\        |          /\        |          /\        |&lt;br /&gt;
            /  \       |         /  \       |         /  \       |&lt;br /&gt;
           /    \ J    |        /    \ J    |        /    \ J    |&lt;br /&gt;
          /F1=0 ?\----&amp;gt;+       /Fn=0 ?\----&amp;gt;+       /F8=0 ?\----&amp;gt;+&lt;br /&gt;
          \      /     A       \      /     |       \      /     |&lt;br /&gt;
           \    /      |        \    /      |        \    /      |&lt;br /&gt;
            \  /       |         \  /       |         \  /       |&lt;br /&gt;
             \/        |          \/        |          \/        |&lt;br /&gt;
              |N       |           |N       |           |N       |&lt;br /&gt;
          +---+--+     |       +---+--+     |       +---+--+     |&lt;br /&gt;
          |      |     |       |      |     |       |      |     |&lt;br /&gt;
          V      |     |       V      |     |       V      |     |&lt;br /&gt;
       .-----.   |     |    .-----.   |     |    .-----.   |     |&lt;br /&gt;
    +-&amp;gt;| AA1 |   |     | +-&amp;gt;| AAn |   |     | +-&amp;gt;| AA8 |   |     |&lt;br /&gt;
    |  '-----'   |     | |  '-----'   |     | |  '-----'   |     |&lt;br /&gt;
    |     |      |     | |     |      |     | |     |      |     |&lt;br /&gt;
    |     V      V     | |     V      V     | |     V      V     |&lt;br /&gt;
    |  .-----..-----.  | |  .-----..-----.  | |  .-----..-----.  |&lt;br /&gt;
    |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
    |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
    |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+&lt;br /&gt;
    |  |     ||  1  |    |  |     ||  n  |    |  |     ||  8  |&lt;br /&gt;
    |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
    |  '-----  -----'    |  '-----  -----'    |  '-----  -----'&lt;br /&gt;
    |     |            | |     |            | |     |            |&lt;br /&gt;
    |     V              |     V              |     V&lt;br /&gt;
    |  .-----.         | |  .-----.         | |  .-----.         |&lt;br /&gt;
    +--| EA1 |&amp;lt;- - - - + +--| EAn |&amp;lt;- - - - + +--| EA8 |&amp;lt;- - - - +&lt;br /&gt;
       '-----'              '-----'              '-----'&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Bei Tabellen, die länger als 256 Byte sind, muss immer PCLATH an den Seitengrenzen korriegiert werden, wie auf der 3. Seite der Applikation Note AN556 vom Microchip vorgestellt: http://ww1.microchip.com/downloads/en/AppNotes/00556e.pdf .&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quellcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quellcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quellcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]] und Anwendung: http://www.roboternetz.de/community/threads/42200-Frequenzz%C3%A4hler-mit-LPH2673-1-%28zum-Nachbauen%29 .&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
Hoffentlich hilfreiche Beiträge sind auch dort zu finden: http://www.roboternetz.de/community/threads/26098-Tips-Tricks .&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quellcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=24842</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=24842"/>
				<updated>2014-07-11T23:06:44Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Multitasking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. &lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Ein sogenannter Prozessortakt besteht aus 4 Oszillator-Takten, die jeweils einen Teil eines Befehls abarbeiten. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. In dieser Form wird auch von Assembler oder kurz ASM gesprochen. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie bis zu 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des großen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Anders als bei einer Hochsprache ist die &amp;quot;Übersetzung&amp;quot; genau vorhersehbar und festgelegt. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich. Bei PIC's ist echtes Multitasking (Parallellaufen) nur mit Timer und ADC Wandler möglich (siehe dazu: http://www.roboternetz.de/community/threads/42200-Frequenzz%C3%A4hler-mit-LPH2673-1-%28zum-Nachbauen%29?highlight=LPH2673-1 ) &lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende ausgeführt. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
        +&amp;lt;---------------------------------------+&lt;br /&gt;
        |                                        |&lt;br /&gt;
        V                                        |&lt;br /&gt;
        /\               /\               /\     |&lt;br /&gt;
       /  \             /  \             /  \    |&lt;br /&gt;
      /    \ J         /    \ J         /    \ J |&lt;br /&gt;
     /F1=0 ?\-&amp;gt;+- - -&amp;gt;/Fn=0 ?\-&amp;gt;+- - -&amp;gt;/F8=0 ?\-&amp;gt;+&lt;br /&gt;
     \      /  A      \      /  A      \      /  A&lt;br /&gt;
      \    /   |       \    /   |       \    /   |&lt;br /&gt;
       \  /    |        \  /    |        \  /    |&lt;br /&gt;
        \/     |         \/     |         \/     |&lt;br /&gt;
        |N     |         |N     |         |N     |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
     .------.  |      .------.  |      .------.  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     | TUN1 |  |      | TUNn |  |      | TUN8 |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     '------'  |      '------'  |      '------'  |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        +------+         +------+         +------+&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer (TMR) unterbrochen und nächster Tast gestartet. Dafür muss immer nach Beenden von jedem Task die Endadresse vom Programm Counter (PC), wo der Task unterbrochen wurde (EA1), auf dem Stapel als nächste Startadresse (AA1) gespeichert werden. Wenn die Zeit für den unterbrochenen Task wieder kommt, wird er ab der unterbrochenen Stelle (AA1) wieder in der ihn zustehenden Zeit ausgeführt, wieder unterbrochen, u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist. Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
        +--------------------------------------------------------+&lt;br /&gt;
        |  .-----.              .-----.              .-----.     |&lt;br /&gt;
        +-&amp;gt;|Task1|----&amp;gt;+- - - -&amp;gt;|Taskn|----&amp;gt;+- - - -&amp;gt;|Task8|----&amp;gt;+&lt;br /&gt;
           '-----'     |        '-----'     |        '-----'     |&lt;br /&gt;
              |        |           |        |           |        |&lt;br /&gt;
              V        |           V        |           V        |&lt;br /&gt;
             /\        |          /\        |          /\        |&lt;br /&gt;
            /  \       |         /  \       |         /  \       |&lt;br /&gt;
           /    \ J    |        /    \ J    |        /    \ J    |&lt;br /&gt;
          /F1=0 ?\----&amp;gt;+       /Fn=0 ?\----&amp;gt;+       /F8=0 ?\----&amp;gt;+&lt;br /&gt;
          \      /     A       \      /     |       \      /     |&lt;br /&gt;
           \    /      |        \    /      |        \    /      |&lt;br /&gt;
            \  /       |         \  /       |         \  /       |&lt;br /&gt;
             \/        |          \/        |          \/        |&lt;br /&gt;
              |N       |           |N       |           |N       |&lt;br /&gt;
          +---+--+     |       +---+--+     |       +---+--+     |&lt;br /&gt;
          |      |     |       |      |     |       |      |     |&lt;br /&gt;
          V      |     |       V      |     |       V      |     |&lt;br /&gt;
       .-----.   |     |    .-----.   |     |    .-----.   |     |&lt;br /&gt;
    +-&amp;gt;| AA1 |   |     | +-&amp;gt;| AAn |   |     | +-&amp;gt;| AA8 |   |     |&lt;br /&gt;
    |  '-----'   |     | |  '-----'   |     | |  '-----'   |     |&lt;br /&gt;
    |     |      |     | |     |      |     | |     |      |     |&lt;br /&gt;
    |     V      V     | |     V      V     | |     V      V     |&lt;br /&gt;
    |  .-----..-----.  | |  .-----..-----.  | |  .-----..-----.  |&lt;br /&gt;
    |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
    |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
    |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+&lt;br /&gt;
    |  |     ||  1  |    |  |     ||  n  |    |  |     ||  8  |&lt;br /&gt;
    |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
    |  '-----  -----'    |  '-----  -----'    |  '-----  -----'&lt;br /&gt;
    |     |            | |     |            | |     |            |&lt;br /&gt;
    |     V              |     V              |     V&lt;br /&gt;
    |  .-----.         | |  .-----.         | |  .-----.         |&lt;br /&gt;
    +--| EA1 |&amp;lt;- - - - + +--| EAn |&amp;lt;- - - - + +--| EA8 |&amp;lt;- - - - +&lt;br /&gt;
       '-----'              '-----'              '-----'&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Bei Tabellen, die länger als 256 Byte sind, muss immer PCLATH an den Seitengrenzen korriegiert werden, wie auf der 3. Seite der Applikation Note AN556 vom Microchip vorgestellt: http://ww1.microchip.com/downloads/en/AppNotes/00556e.pdf .&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quellcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quellcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quellcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
Hoffentlich hilfreiche Beiträge sind auch dort zu finden: http://www.roboternetz.de/community/threads/26098-Tips-Tricks .&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quellcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=24841</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=24841"/>
				<updated>2014-07-11T23:04:19Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Multitasking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. &lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Ein sogenannter Prozessortakt besteht aus 4 Oszillator-Takten, die jeweils einen Teil eines Befehls abarbeiten. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. In dieser Form wird auch von Assembler oder kurz ASM gesprochen. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie bis zu 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des großen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Anders als bei einer Hochsprache ist die &amp;quot;Übersetzung&amp;quot; genau vorhersehbar und festgelegt. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich. Bei PIC's ist echtes Multitasking (Parallellaufen) nur mit Timer und ADC Wandler möglich (siehe dazu: http://www.roboternetz.de/community/threads/42200-Frequenzz%C3%A4hler-mit-LPH2673-1-%28zum-Nachbauen%29?highlight=LPH2673-1 ) &lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende ausgeführt. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
        +&amp;lt;---------------------------------------+&lt;br /&gt;
        |                                        |&lt;br /&gt;
        V                                        |&lt;br /&gt;
        /\               /\               /\     |&lt;br /&gt;
       /  \             /  \             /  \    |&lt;br /&gt;
      /    \ J         /    \ J         /    \ J |&lt;br /&gt;
     /F1=0 ?\-&amp;gt;+- - -&amp;gt;/Fn=0 ?\-&amp;gt;+- - -&amp;gt;/F8=0 ?\-&amp;gt;+&lt;br /&gt;
     \      /  A      \      /  A      \      /  A&lt;br /&gt;
      \    /   |       \    /   |       \    /   |&lt;br /&gt;
       \  /    |        \  /    |        \  /    |&lt;br /&gt;
        \/     |         \/     |         \/     |&lt;br /&gt;
        |N     |         |N     |         |N     |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
     .------.  |      .------.  |      .------.  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     | TUN1 |  |      | TUNn |  |      | TUN8 |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     '------'  |      '------'  |      '------'  |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        +------+         +------+         +------+&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer (TMR) unterbrochen und nächster Tast gestartet. Dafür muss immer nach Beenden von jedem Task die Endadresse vom Programm Counter (PC), wo der Task unterbrochen wurde (EA1), auf dem Stapel als nächste Startadresse (AA1) gespeichert werden. Wenn die Zeit für den unterbrochenen Task wieder kommt, wird er ab der unterbrochenen Stelle (AA1) wieder in der ihn zustehenden Zeit ausgeführt, wieder unterbrochen, u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist. Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
        +--------------------------------------------------------+&lt;br /&gt;
        |  .-----.              .-----.              .-----.     |&lt;br /&gt;
        +-&amp;gt;|Task1|----&amp;gt;+- - - -&amp;gt;|Taskn|----&amp;gt;+- - - -&amp;gt;|Task8|----&amp;gt;+&lt;br /&gt;
           '-----'     |        '-----'     |        '-----'     |&lt;br /&gt;
              |        |           |        |           |        |&lt;br /&gt;
              V        |           V        |           V        |&lt;br /&gt;
             /\        |          /\        |          /\        |&lt;br /&gt;
            /  \       |         /  \       |         /  \       |&lt;br /&gt;
           /    \ J    |        /    \ J    |        /    \ J    |&lt;br /&gt;
          /F1=0 ?\----&amp;gt;+       /Fn=0 ?\----&amp;gt;+       /F8=0 ?\----&amp;gt;+&lt;br /&gt;
          \      /     A       \      /     |       \      /     |&lt;br /&gt;
           \    /      |        \    /      |        \    /      |&lt;br /&gt;
            \  /       |         \  /       |         \  /       |&lt;br /&gt;
             \/        |          \/        |          \/        |&lt;br /&gt;
              |N       |           |N       |           |N       |&lt;br /&gt;
          +---+--+     |       +---+--+     |       +---+--+     |&lt;br /&gt;
          |      |     |       |      |     |       |      |     |&lt;br /&gt;
          V      |     |       V      |     |       V      |     |&lt;br /&gt;
       .-----.   |     |    .-----.   |     |    .-----.   |     |&lt;br /&gt;
    +-&amp;gt;| AA1 |   |     | +-&amp;gt;| AAn |   |     | +-&amp;gt;| AA8 |   |     |&lt;br /&gt;
    |  '-----'   |     | |  '-----'   |     | |  '-----'   |     |&lt;br /&gt;
    |     |      |     | |     |      |     | |     |      |     |&lt;br /&gt;
    |     V      V     | |     V      V     | |     V      V     |&lt;br /&gt;
    |  .-----..-----.  | |  .-----..-----.  | |  .-----..-----.  |&lt;br /&gt;
    |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
    |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
    |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+&lt;br /&gt;
    |  |     ||  1  |    |  |     ||  n  |  A |  |     ||  8  |&lt;br /&gt;
    |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
    |  '-----  -----'    |  '-----  -----'    |  '-----  -----'&lt;br /&gt;
    |     |            | |     |            | |     |            |&lt;br /&gt;
    |     V              |     V              |     V&lt;br /&gt;
    |  .-----.         | |  .-----.         | |  .-----.         |&lt;br /&gt;
    +--| EA1 |&amp;lt;- - - - + +--| EAn |&amp;lt;- - - - + +--| EA8 |&amp;lt;- - - - +&lt;br /&gt;
       '-----'              '-----'              '-----'&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Bei Tabellen, die länger als 256 Byte sind, muss immer PCLATH an den Seitengrenzen korriegiert werden, wie auf der 3. Seite der Applikation Note AN556 vom Microchip vorgestellt: http://ww1.microchip.com/downloads/en/AppNotes/00556e.pdf .&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quellcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quellcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quellcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
Hoffentlich hilfreiche Beiträge sind auch dort zu finden: http://www.roboternetz.de/community/threads/26098-Tips-Tricks .&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quellcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=24840</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=24840"/>
				<updated>2014-07-11T22:58:41Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Multitasking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. &lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Ein sogenannter Prozessortakt besteht aus 4 Oszillator-Takten, die jeweils einen Teil eines Befehls abarbeiten. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. In dieser Form wird auch von Assembler oder kurz ASM gesprochen. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie bis zu 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des großen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Anders als bei einer Hochsprache ist die &amp;quot;Übersetzung&amp;quot; genau vorhersehbar und festgelegt. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich. Bei PIC's ist echtes Multitasking (Parallellaufen) nur mit Timer und ADC Wandler möglich (siehe dazu: http://www.roboternetz.de/community/threads/42200-Frequenzz%C3%A4hler-mit-LPH2673-1-%28zum-Nachbauen%29?highlight=LPH2673-1 ) &lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende ausgeführt. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
        +&amp;lt;---------------------------------------+&lt;br /&gt;
        |                                        |&lt;br /&gt;
        V                                        |&lt;br /&gt;
        /\               /\               /\     |&lt;br /&gt;
       /  \             /  \             /  \    |&lt;br /&gt;
      /    \ J         /    \ J         /    \ J |&lt;br /&gt;
     /F1=0 ?\-&amp;gt;+- - -&amp;gt;/Fn=0 ?\-&amp;gt;+- - -&amp;gt;/F8=0 ?\-&amp;gt;+&lt;br /&gt;
     \      /  A      \      /  A      \      /  A&lt;br /&gt;
      \    /   |       \    /   |       \    /   |&lt;br /&gt;
       \  /    |        \  /    |        \  /    |&lt;br /&gt;
        \/     |         \/     |         \/     |&lt;br /&gt;
        |N     |         |N     |         |N     |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
     .------.  |      .------.  |      .------.  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     | TUN1 |  |      | TUNn |  |      | TUN8 |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     '------'  |      '------'  |      '------'  |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        +------+         +------+         +------+&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer (TMR) unterbrochen und nächster Tast gestartet. Dafür muss immer nach Beenden von jedem Task die Endadresse vom Programm Counter (PC), wo der Task unterbrochen wurde (EA1), auf dem Stapel als nächste Startadresse (AA1) gespeichert werden. Wenn die Zeit für den unterbrochenen Task wieder kommt, wird er ab der unterbrochenen Stelle (AA1) wieder in der ihn zustehenden Zeit ausgeführt, wieder unterbrochen, u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist. Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
         +--------------------------------------------------------+&lt;br /&gt;
         |  .-----.              .-----.              .-----.     |&lt;br /&gt;
         +-&amp;gt;|Task1|----&amp;gt;+- - - -&amp;gt;|Taskn|----&amp;gt;+- - - -&amp;gt;|Task8|----&amp;gt;+&lt;br /&gt;
            '-----'     |        '-----'     |        '-----'     |&lt;br /&gt;
               |        |           |        |           |        |&lt;br /&gt;
               V        |           V        |           V        |&lt;br /&gt;
              /\        |          /\        |          /\        |&lt;br /&gt;
             /  \       |         /  \       |         /  \       |&lt;br /&gt;
            /    \ J    |        /    \ J    |        /    \ J    |&lt;br /&gt;
           /F1=0 ?\----&amp;gt;+       /Fn=0 ?\----&amp;gt;+       /F8=0 ?\----&amp;gt;+&lt;br /&gt;
           \      /     A       \      /     |       \      /     |&lt;br /&gt;
            \    /      |        \    /      |        \    /      |&lt;br /&gt;
             \  /       |         \  /       |         \  /       |&lt;br /&gt;
              \/        |          \/        |          \/        |&lt;br /&gt;
               |N       |           |N       |           |N       |&lt;br /&gt;
           +---+--+     |       +---+--+     |       +---+--+     |&lt;br /&gt;
           |      |     |       |      |     |       |      |     |&lt;br /&gt;
           V      |     |       V      |     |       V      |     |&lt;br /&gt;
        .-----.   |     |    .-----.   |     |    .-----.   |     |&lt;br /&gt;
     +-&amp;gt;| AA1 |   |     | +-&amp;gt;| AAn |   |     | +-&amp;gt;| AA8 |   |     |&lt;br /&gt;
     |  '-----'   |     | |  '-----'   |     | |  '-----'   |     |&lt;br /&gt;
     |     |      |     | |     |      |     | |     |      |     |&lt;br /&gt;
     |     V      V     | |     V      V     | |     V      V     |&lt;br /&gt;
     |  .-----..-----.  | |  .-----..-----.  | |  .-----..-----.  |&lt;br /&gt;
     |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
     |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
     |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+&lt;br /&gt;
     |  |     ||  1  |    |  |     ||  n  |  A |  |     ||  8  |&lt;br /&gt;
     |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
     |  '-----''-----'    |  '-----''-----'    |  '-----''-----'&lt;br /&gt;
     |     |            | |     |            | |     |            |&lt;br /&gt;
     |     V              |     V              |     V&lt;br /&gt;
     |  .-----.         | |  .-----.         | |  .-----.         |&lt;br /&gt;
     +--| EA1 |&amp;lt;- - - - + +--| EAn |&amp;lt;- - - - + +--| EA8 |&amp;lt;- - - - +&lt;br /&gt;
        '-----'              '-----'              '-----'&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Bei Tabellen, die länger als 256 Byte sind, muss immer PCLATH an den Seitengrenzen korriegiert werden, wie auf der 3. Seite der Applikation Note AN556 vom Microchip vorgestellt: http://ww1.microchip.com/downloads/en/AppNotes/00556e.pdf .&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quellcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quellcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quellcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
Hoffentlich hilfreiche Beiträge sind auch dort zu finden: http://www.roboternetz.de/community/threads/26098-Tips-Tricks .&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quellcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=24839</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=24839"/>
				<updated>2014-07-11T22:53:45Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Multitasking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. &lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Ein sogenannter Prozessortakt besteht aus 4 Oszillator-Takten, die jeweils einen Teil eines Befehls abarbeiten. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. In dieser Form wird auch von Assembler oder kurz ASM gesprochen. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie bis zu 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des großen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. &lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Anders als bei einer Hochsprache ist die &amp;quot;Übersetzung&amp;quot; genau vorhersehbar und festgelegt. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich. Bei PIC's ist echtes Multitasking (Parallellaufen) nur mit Timer und ADC Wandler möglich (siehe dazu: http://www.roboternetz.de/community/threads/42200-Frequenzz%C3%A4hler-mit-LPH2673-1-%28zum-Nachbauen%29?highlight=LPH2673-1 ) &lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende ausgeführt. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
        +&amp;lt;---------------------------------------+&lt;br /&gt;
        |                                        |&lt;br /&gt;
        V                                        |&lt;br /&gt;
        /\               /\               /\     |&lt;br /&gt;
       /  \             /  \             /  \    |&lt;br /&gt;
      /    \ J         /    \ J         /    \ J |&lt;br /&gt;
     /F1=0 ?\-&amp;gt;+- - -&amp;gt;/Fn=0 ?\-&amp;gt;+- - -&amp;gt;/F8=0 ?\-&amp;gt;+&lt;br /&gt;
     \      /  A      \      /  A      \      /  A&lt;br /&gt;
      \    /   |       \    /   |       \    /   |&lt;br /&gt;
       \  /    |        \  /    |        \  /    |&lt;br /&gt;
        \/     |         \/     |         \/     |&lt;br /&gt;
        |N     |         |N     |         |N     |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
     .------.  |      .------.  |      .------.  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     | TUN1 |  |      | TUNn |  |      | TUN8 |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     |      |  |      |      |  |      |      |  |&lt;br /&gt;
     '------'  |      '------'  |      '------'  |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        V      |         V      |         V      |&lt;br /&gt;
        |      |         |      |         |      |&lt;br /&gt;
        +------+         +------+         +------+&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer (TMR) unterbrochen und nächster Tast gestartet. Dafür muss immer nach Beenden von jedem Task die Endadresse vom Programm Counter (PC), wo der Task unterbrochen wurde (EA1), auf dem Stapel als nächste Startadresse (AA1) gespeichert werden. Wenn die Zeit für den unterbrochenen Task wieder kommt, wird er ab der unterbrochenen Stelle (AA1) wieder in der ihn zustehenden Zeit ausgeführt, wieder unterbrochen, u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist. Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
         +--------------------------------------------------------+&lt;br /&gt;
         |  .-----.              .-----.              .-----.     |&lt;br /&gt;
         +-&amp;gt;|Task1|----&amp;gt;+- - - -&amp;gt;|Taskn|----&amp;gt;+- - - -&amp;gt;|Task8|----&amp;gt;+&lt;br /&gt;
            '-----'     |        '-----'     |        '-----'     |&lt;br /&gt;
               |        |           |        |           |        |&lt;br /&gt;
               V        |           V        |           V        |&lt;br /&gt;
              /\        |          /\        |          /\        |&lt;br /&gt;
             /  \       |         /  \       |         /  \       |&lt;br /&gt;
            /    \ J    |        /    \ J    |        /    \ J    |&lt;br /&gt;
           /F1=0 ?\----&amp;gt;+       /Fn=0 ?\----&amp;gt;+       /F8=0 ?\----&amp;gt;+&lt;br /&gt;
           \      /     A       \      /     |       \      /     |&lt;br /&gt;
            \    /      |        \    /      |        \    /      |&lt;br /&gt;
             \  /       |         \  /       |         \  /       |&lt;br /&gt;
              \/        |          \/        |          \/        |&lt;br /&gt;
               |N       |           |N       |           |N       |&lt;br /&gt;
           +---+--+     |       +---+--+     |       +---+--+     |&lt;br /&gt;
           |      |     |       |      |     |       |      |     |&lt;br /&gt;
           V      |     |       V      |     |       V      |     |&lt;br /&gt;
        .-----.   |     |    .-----.   |     |    .-----.   |     |&lt;br /&gt;
     +-&amp;gt;| AA1 |   |     | +-&amp;gt;| AAn |   |     | +-&amp;gt;| AA8 |   |     |&lt;br /&gt;
     |  '-----'   |     | |  '-----'   |     | |  '-----'   |     |&lt;br /&gt;
     |     |      |     | |     |      |     | |     |      |     |&lt;br /&gt;
     |     V      V     | |     V      V     | |     V      V     |&lt;br /&gt;
     |  .-----..-----.  | |  .-----..-----.  | |  .-----..-----.  |&lt;br /&gt;
     |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
     |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
     |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+ |  | TMR || Tun |-&amp;gt;+&lt;br /&gt;
     |  |     ||  1  |    |  |     ||  n  |  A |  |     ||  8  |&lt;br /&gt;
     |  |     ||     |  | |  |     ||     |  | |  |     ||     |  |&lt;br /&gt;
     |  '-----''-----'    |  '-----''-----'    |  '-----''-----'&lt;br /&gt;
     |     |            | |     |            | |     |            |&lt;br /&gt;
     |     V              |     V              |     V&lt;br /&gt;
     |  .-----.         | |  .-----.         | |  .-----.         |&lt;br /&gt;
     +--| EA1 |&amp;lt;- - - - + +--| EAn |&amp;lt;- - - - + +--| EA8 |&amp;lt;- - - - +&lt;br /&gt;
        '-----'              '-----'              '-----'&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Bei Tabellen, die länger als 256 Byte sind, muss immer PCLATH an den Seitengrenzen korriegiert werden, wie auf der 3. Seite der Applikation Note AN556 vom Microchip vorgestellt: http://ww1.microchip.com/downloads/en/AppNotes/00556e.pdf .&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quellcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quellcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quellcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
Hoffentlich hilfreiche Beiträge sind auch dort zu finden: http://www.roboternetz.de/community/threads/26098-Tips-Tricks .&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quellcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=23374</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=23374"/>
				<updated>2013-12-07T10:21:35Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Tabellen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich. Bei PIC's ist echtes Multitasking (Parallellaufen) nur mit Timer und ADC Wandler möglich (siehe dazu: http://www.roboternetz.de/community/threads/42200-Frequenzz%C3%A4hler-mit-LPH2673-1-%28zum-Nachbauen%29?highlight=LPH2673-1 ) &lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende realisiert. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer unterbrochen und nächster Tast gestartet. Dafür muss immer nach Beenden der ISR unbedingt ins HP gesprungen werden und die Adresse vom PC, wo der Task unterbrochen wurde auf dem Stapel gespeichert werden. Wenn die Zeit für den unterbrochenen Task wieder kommt, wird er ab der unterbrochenen Stelle wieder in der ihn zustehenden Zeit ausgeführt, wieder unterbrochen u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Bei Tabellen, die länger als 256 Byte sind, muss immer PCLATH an den Seitengrenzen korriegiert werden, wie auf der 3. Seite der Applikation Note AN556 vom Microchip vorgestellt: http://ww1.microchip.com/downloads/en/AppNotes/00556e.pdf .&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quellcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quellcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quellcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
Hoffentlich hilfreiche Beiträge sind auch dort zu finden: http://www.roboternetz.de/community/threads/26098-Tips-Tricks .&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quellcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Diskussion:Sourcecode_generieren&amp;diff=23030</id>
		<title>Diskussion:Sourcecode generieren</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Diskussion:Sourcecode_generieren&amp;diff=23030"/>
				<updated>2013-10-14T10:18:40Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Eindeutig Spam, will am Ende zum Kauf der Software bzw. zum Test einer eingeschränkten Version überreden.&lt;br /&gt;
&lt;br /&gt;
Hallo! Ich bin gleicher Meinung und finde es in RN-Wissen sinnlos. MfG PICture.&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Diskussion:Sourcecode_generieren&amp;diff=23029</id>
		<title>Diskussion:Sourcecode generieren</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Diskussion:Sourcecode_generieren&amp;diff=23029"/>
				<updated>2013-10-14T10:17:49Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Eindeutig Spam, will am Ende zum Kauf der Software bzw. zum Test einer eingeschränkten Version überreden.&lt;br /&gt;
&lt;br /&gt;
Hallo!&lt;br /&gt;
Ich bin gleicher Meinung und finde es in RN-Wissen sinnlos.&lt;br /&gt;
MfG PICture.&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Diskussion:Sourcecode_generieren&amp;diff=23028</id>
		<title>Diskussion:Sourcecode generieren</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Diskussion:Sourcecode_generieren&amp;diff=23028"/>
				<updated>2013-10-14T10:12:26Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Eindeutig Spam, will am Ende zum Kauf der Software bzw. zum Test einer eingeschränkten Version überreden.&lt;br /&gt;
&lt;br /&gt;
Ich bin gleicher Meinung und finde es in RN-Wissen sinnlos.&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Bezugsquellen&amp;diff=21444</id>
		<title>Bezugsquellen</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Bezugsquellen&amp;diff=21444"/>
				<updated>2012-11-19T10:44:30Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| {{Blaueschmaltabelle}}&lt;br /&gt;
|Hier können Bezugsquellen eingetragen werden! Bitte aber pro Eintrag nicht mehr als '''2 bis 3 Zeilen''', ansonsten muss es ein Moderator kürzen! Dieser Artikel soll nicht als Werbeplattform mißbraucht werden, für Werbung gibts andere [[RN-Wissen:Site_support|Möglichkeiten]]. Er soll eine Hilfe für Bastler sein. '''Daher sollen hier auch nur Firmen eingetragen werden, welche eine Bestellmöglichkeit Webformular oder Online-Shop bereitstellen'''.&lt;br /&gt;
Bitte auch keine Bewertungen der Lieferanten vornehmen, das ist Sache der Leser &amp;amp; Bastler indem Sie vergleichen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Elektronikbauteile==&lt;br /&gt;
&lt;br /&gt;
;Rehag - http://www.rehag.de: Optoelektronische Bauteile für Groß- und Kleinkunden.&lt;br /&gt;
&lt;br /&gt;
;Conrad - http://www.conrad.de: Fast alle Standardelektronikbauteile&lt;br /&gt;
&lt;br /&gt;
;CSD-Electronic - http://www.csd-electronics.de/: Elektronik&lt;br /&gt;
&lt;br /&gt;
;Digi-Key Corporation - http://de.digikey.com/: Diverse Bauelemente, Microcontroller, Sensoren, auch 'exotische' Bauteile, sehr umfangreiches Sortiment, kostenloser Katalog, Suchfunktion nach Parametern&lt;br /&gt;
&lt;br /&gt;
;Distrelec Gruppe - http://www.distrelec.com: Ableger in vielen Ländern, Diverse Bauelemente (aktiv, passiv, Microcontroller), Literatur, PC-Komponenten, usw.&lt;br /&gt;
&lt;br /&gt;
;Farnell In One - http://de.farnell.com/: elektronische Bauelemente (aktiv, passiv, Microcontroller), Sensoren, Literatur, Entwicklungskits, Kabel, Steckverbinder, Werkstattbedarf. Beliefert nur (bel.) angemeldete '''Gewerbe und Stud.''' (mit Nachweis) Nicht für privat. Sehr schnell. Sehr gut Sortiert (auch &amp;quot;exotische&amp;quot; Bauelemente)&lt;br /&gt;
&lt;br /&gt;
;HBE-Shop Farnell auch für Privat - http://www.hbe-shop.de: HBE Fachhändler für FARNELL, Ab einem Warenwert von 50,00 € (netto) Standardpakete versandkostenfrei.&lt;br /&gt;
&lt;br /&gt;
;Robotik-Teile.de - http://www.robotik-teile.de: Aktive und Passive Bauelemente, Microcontroller, Controllerboards, etc. Versandkosten pauschal: 4,90 €&lt;br /&gt;
&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Microcontroller, spezielle Controller und einige schwer erhältliche Bauteile (auch SMD)&lt;br /&gt;
&lt;br /&gt;
;Kessler-Electronic - http://www.kessler-electronic.de/: ( ehemals Simons ) Diverse Bauelemente (aktiv, passiv, Microcontroller), Literatur, PC-Komponenten, Messgeräte, Hifi, usw. Preisstaffelung für größere Mengen, Mindestbestellwert: 10 Euro&lt;br /&gt;
&lt;br /&gt;
;marsch-elektronik - http://www.marsch-elektronik.de/: Diverse Bauelemente (aktiv, passiv, Mikrocontroller, LEDs), kein Mindestbestellwert, niedrige Versandkosten (ab 40 Euro versandkostenfrei). Es werden auch sogenannte &amp;quot;Einsteigersortimente&amp;quot; und Widerstandssortimente (auch SMD) angeboten. Nicht gelistete Bauelemente können angefragt werden.&lt;br /&gt;
&lt;br /&gt;
;Neuhold Electronik - http://www.neuhold-elektronik.at: Restposten&lt;br /&gt;
&lt;br /&gt;
;no DNA - http://www.nodna.com/: Diverse Roboterbauteile, Sensoren und komplette Roboter; keine Bauelemente wie Widerstände, Transistoren etc. Viel Zubehör vom amerikanischen Markt. Keine Mindestbestellmenge.&lt;br /&gt;
&lt;br /&gt;
;Pollin Electronic - http://www.pollin.de/: Diverse Bauelemente und Sortimente zu Spottpreisen, fast alles Restposten oder Gebrauchte Teile, daher kein beständiges Sortiment&lt;br /&gt;
&lt;br /&gt;
;Reichelt - http://www.reichelt.de: Diverse Bauelemente (aktiv, passiv, Microcontroller), Literatur, PC-Komponenten, Lichttechnik, Messtechnik, Software,  Kabel, Steckverbinder, Werkstattbedarf, Werkzeug,  Mindestbestellwert: 10 Euro&lt;br /&gt;
&lt;br /&gt;
;RS-Components - http://www.rsonline.de: Bauelemente: (aktiv, passiv, Microcontroller), Literatur, PC-Komponenten, Lichttechnik, Messtechnik, Software, Kabel, Steckverbinder, Werkzeug&lt;br /&gt;
&lt;br /&gt;
;Ribu Elektronik - http://www.ribu.at: Diverse Bauelemente, ICs, österreichische Seite&lt;br /&gt;
&lt;br /&gt;
;guloshop.de - http://guloshop.de: nur wenige Standard-Mikrocontroller, diese aber zu sehr niedrigen Preisen (Mikrocontroller-Discounter). Versandkosten bei Bestellungen bis 10 Euro: 2,40 Euro, sonst 4,40 Euro.&lt;br /&gt;
&lt;br /&gt;
==Sensoren==&lt;br /&gt;
&lt;br /&gt;
;Robotik-Teile.de - http://www.robotik-teile.de: Beschleunigungssensoren, Gyros &amp;amp; Komapsse, Gas-Sensoren, Infrarotsensoren, Stromsensoren und Ultraschallsensoren. Versandkosten pauschal: 4,90 €&lt;br /&gt;
&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Drehgeber, Sharp-Entfernungssensoren, Ultraschallsensoren, Neigungssensoren, Temperatursensoren, Hallsensoren, Beschleunigungssensoren Magnete usw. speziell für Robotik-Bastler&lt;br /&gt;
&lt;br /&gt;
;MANU SYSTEMS - http://de.manu-systems.com/ROBOT_ELECTRONICS.shtml: Ultraschallsensoren, Kompassmodule, Temperatursensor Array&lt;br /&gt;
&lt;br /&gt;
;Micromaus - http://www.micromaus.de: Sharp-Entfernungssensoren, Farbsensoren, Feuchtesensoren, Flexsensoren, Beschleunigungssensoren, Drucksensoren usw.&lt;br /&gt;
&lt;br /&gt;
;Roboter-Teile - http://www.roboter-teile.de/ : Lynxmotion Hexapot, Sensoren, CMU-Cam, AVR, PIC u.v.a.&lt;br /&gt;
&lt;br /&gt;
;Conrad - http://www.conrad.de: Fast alle Standardelektronikbauteile&lt;br /&gt;
&lt;br /&gt;
;Digi-Key Corporation - http://de.digikey.com/: Diverse Bauelemente, Microcontroller, Sensoren, auch 'exotische' Bauteile, sehr umfangreiches Sortiment, kostenloser Katalog. Hohe Versandkosten (über 30 Euro selbst bei Kleinteilen)&lt;br /&gt;
&lt;br /&gt;
;Krause Robotik - http://www.krause-robotik.de/Shop/: Diverse Sensoren und Mikrocontrollerboards. 4,65 € Versand&lt;br /&gt;
&lt;br /&gt;
;austriamicrosystems - http://www.austriamicrosystems.com/: Winkelencoder auf magnetischer Hallbasis, diverse analoge Komponenten, bsp. A/D converter, LDOs, Watchdog, I/O Expanderchips. Muster und kleine Stückzahlen koennen direkt ueber https://shop.austriamicrosystems.com/ bestellt werden.&lt;br /&gt;
&lt;br /&gt;
;WayCon Positionsmesstechnik - http://www.waycon.de : Seilzugsensor, Induktiver Sensor LVDT, Wirbelstrom, Lasersensor, Digitales Magnetband, Digitaler Messtaster, Digitaler Maßstab, Linearpotentiometer, Magnetostriktive Geber, Ultraschall, Anzeigen u Displays, Endocder u Winkelgeber&lt;br /&gt;
&lt;br /&gt;
==Motoren und Schrittmotoren== &lt;br /&gt;
;Siebert-Industrie - http://shop.siebert-industrie.de: Schrittmotoren, Steuerungen, Logik-Controller, antriebstechnische Komponenten und Baugruppen für die Automatisierung. Bauteile auch für Extrembedingungen (Weltraum, Vakuum, Reinraum, Temperaturen)&lt;br /&gt;
&lt;br /&gt;
;mir-elektronik - http://www.mir-elektronik.de: Schrittmotoren, Endstufen, Bauteile, Literatur und Sonderposten&lt;br /&gt;
;Lemo-Solar - http://lemo-solar.de/: Motoren, Getriebe, Elektronik-Bausätze, Sonderposten u.v.a.&lt;br /&gt;
&lt;br /&gt;
;Robotik-Teile.de - http://www.robotik-teile.de: Metall-Getriebemotoren, Plastik-Getriebemotoren, Schrittmotoren, Servos, Solarbotics Getriebe und Tamiya Motoren und Getriebe. Versandkosten pauschal: 4,90 €&lt;br /&gt;
&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Schrittmotor-Angebote, Tamiya Modellbau Getriebemotoren, Devantech Getriebemotoren mit eingebauten Drehgeber&lt;br /&gt;
&lt;br /&gt;
;Conrad - http://www.conrad.de: Fast alle Standardelektronikbauteile&lt;br /&gt;
&lt;br /&gt;
;Nanotec - http://www.nanotec.de: Schrittmotoren für Industrieeinsatz, aber Einzelabnahme möglich&lt;br /&gt;
&lt;br /&gt;
;seacontrol - http://www.seacontrol.de: Ist komischerweise ein Aquaristikshop, hat aber auch Schrittmotoren (aus der eigenen Entwicklungsapteilung, oder so) von der Startseite in den online-shop, im shop unten links findet mann die Motoren&lt;br /&gt;
&lt;br /&gt;
;Farnell In One - http://de.farnell.com/: elektronische Bauelemente (aktiv, passiv, Microcontroller), Motoren, Schrittmotoren, Linearmotoren, Sensoren, Literatur, Entwicklungskits, Kabel, Steckverbinder, Werkstattbedarf. Beliefert nur (bel.) angemeldete '''Gewerbe und Stud'''. (mit Nachweis) Nicht für privat. Sehr schnell. Sehr gut Sortiert (auch &amp;quot;exotische&amp;quot; Bauelemente)&lt;br /&gt;
&lt;br /&gt;
==Platinen==&lt;br /&gt;
&lt;br /&gt;
;Multi PCB Ltd. - Leiterplatten - http://www.multipcb.de: Leiterplatten-Discount mit 1-48 Lagen im Online-Kalkulator. Ab 48h Express. Service nur für gewerbliche Kunden.&lt;br /&gt;
&lt;br /&gt;
;PCB-Pool - http://pcb-pool.com: Platinenservice für private und gewerbliche Kunden.&lt;br /&gt;
&lt;br /&gt;
;ANDUS ELECTRONIC GmbH - www.andus.de http://www.andus.de: High-End Leiterplatten und Express-Prototypen in allen Technologien (Multilayer, flexible Leiterplatten, Starrflex,...). Persönliche Technologieberatung für Aufbau und Design von Leiterplatten.&lt;br /&gt;
&lt;br /&gt;
;Robotikhardware.de - http://www.robotikhardware.de: Preiswerte Standard Platinen (beste Industriequalität mit E-Prüfung) zu sehr vielen Robotik- und Microcontrollerschaltungen, inkl. Bauanleitung und Beispielprogrammen.&lt;br /&gt;
&lt;br /&gt;
;LeitOn GmbH - www.leiton.de - http://www.leiton.de: Leiterplatten sofort online kalkulieren und bestellen. Expressdienste von 1 bis 10 Lagen Multilayer in deutscher Industriequalität. Flexible Leiterplatten online kalkulieren. Für Privat und Firmen! Ab 12h.&lt;br /&gt;
&lt;br /&gt;
;Top Tec PCB Ltd. - http://www.top-tec-pcb.de: Günstige Leiterplatten vom Prototyp bis zur Groß-Serie. Viele High-Tech-Optionen sind schon Inklusive.&lt;br /&gt;
&lt;br /&gt;
;Basista Leiterplatten GmbH - http://www.basista.de: Leiterplatten ab 8 Stunden Express-Service. RoHS-konforme Profi-Qualität, mit Onlinekalkulation. Für private und gewerbliche Kunden.&lt;br /&gt;
&lt;br /&gt;
;LFG Oertel - http://www.lfg-oertel.de: Leiterplattenherstellung und Bestückung aus einer Hand. Fertigung und Bestückung ab 1 Stück. Für gewerbliche Kunden.&lt;br /&gt;
&lt;br /&gt;
;GLS Leiterplatten-Service GmbH - http://www.leiterplattenprototypen.de: Prototypenfertigung für Leiterplatten bei Chemnitz bietet zusätzlich viele Serviceleistungen rund um die Leiterplatte (z.B. Scannen/Digitalisieren von Leiterplatten und Leiterplattenlayouts)&lt;br /&gt;
&lt;br /&gt;
;D-E-K Dischereit - http://www.dischereit.de: Preiswerter Komplettservice für die Leiterplattenbestückung von Prototypen und Kleinserien.&lt;br /&gt;
&lt;br /&gt;
;pcb-joker - http://www.pcb-joker.com: Leiterplatten sofort online kalkulieren und bestellen. Von 1 bis 4 Lagen Multilayer. Für Privat und Firmen!&lt;br /&gt;
&lt;br /&gt;
==Anzeigen / LCD's==&lt;br /&gt;
;Display3000 - http://www.shop.display3000.de: Farbdisplays, TFTs, Touchscreens, Mikrocontrollermodule&lt;br /&gt;
&lt;br /&gt;
;Siebert-Industrie - http://shop.siebert-industrie.de: Schrittmotoren, Steuerungen, Logik-Controller, antriebstechnische Komponenten und Baugruppen für die Automatisierung. Bauteile auch für Extrembedingungen (Weltraum, Vakuum, Reinraum, Temperaturen)&lt;br /&gt;
&lt;br /&gt;
;IbS Sperling - http://www.ibs-display.de: LCD-Module, Grafik-LCD, TouchScreens&lt;br /&gt;
&lt;br /&gt;
;Conrad - http://www.conrad.de: Fast alle Standardelektronikbauteile&lt;br /&gt;
&lt;br /&gt;
;Electronic Assembly - http://www.lcdmodule.de: LCD-Module, Grafik-LCD, dog&lt;br /&gt;
&lt;br /&gt;
;LEDsee - http://www.ledsee.com: LED's, Lumeon, LCD's Grafik-LCD, pLED, oLED, Zubehör (Direktversand aus Japan, relativ schnell ca. 1 Woche)&lt;br /&gt;
&lt;br /&gt;
;Robotik-Teile.de - http://www.robotik-teile.de: Einige Standard LCD´s. Versandkosten pauschal: 4,90 € &lt;br /&gt;
&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Verschiedene LCD´s sowie Adapter zum Anschluss an Boards nach Roboternetz-Definition (passend zu [[RN-Control]], [[RN-MiniControl]] usw.)&lt;br /&gt;
&lt;br /&gt;
==Materialien==&lt;br /&gt;
;TECHNOPLAST - http://www.technoplast-onlineshop.de/: Technische Kunststoff Halbzeuge Polycarbonat Platten Plexiglas Acrylglas Rundstäbe Rohre ...&lt;br /&gt;
&lt;br /&gt;
;Opitec - http://www.opitec.de/: Elektromotoren, zahlreiche Zahnräder, Werkzeuge, Räder, diverse Materialien (Kunststoff, Gummi, Papier, Pappe, Holz, Metall, Textilien, Plexiglas ...)&lt;br /&gt;
&lt;br /&gt;
;Robotik-Teile.de - http://www.robotik-teile.de/: Verschiedene Schrauben, Muttern, Steckverbindungen, etc. Versandkosten pauschal: 4,90 € &lt;br /&gt;
&lt;br /&gt;
;Metall Store - http://www.metallstore.de/: Schrittmotoren, (Kugel-)Lager, diverse Bauelemente aus Alu, VA, Messing, Bronze, Kupfer, Werkzeuge, Spezialschrauben&lt;br /&gt;
&lt;br /&gt;
;Modulor - http://www.modulor.de/: Diverse Materialien Kunststoff, Gummi, Papier, Pappe, Holz, Metall, Textilien, Plexiglas ...&lt;br /&gt;
&lt;br /&gt;
;Igus - http://www.igus.de/: Gleitlager, Lineargleitlager, Kabelschleppen, Gelenklager, Polymergleitlager, Wellen ...&lt;br /&gt;
&lt;br /&gt;
;Kienzle Plexiglas - http://www.ernst-kienzle.de/: Acrylglas, Polycarbonat, Polyethylenterephtalatglycol (in vielen Farben, auch Formen machbar)&lt;br /&gt;
&lt;br /&gt;
;Maedler - http://www.maedler.de/: Antriebselemente und Normteile, Getriebe und Getriebemotoren, Pneumatikelemente, Zahnriemen, Zahnriemenräder, div. Lager ...&lt;br /&gt;
&lt;br /&gt;
;Octamex - http://www.octamex.de/: Leiterplatten (in versch. Dicken), Chemikalien zum Ätzen und Veredeln, Elektronikbauteile, Lötstop- und Bestückungsdruck-Laminate, Gehäusetechnik&lt;br /&gt;
&lt;br /&gt;
;Lelebeck - http://www.lelebeck.de/index.htm : Verbindungselemente, Mech. Sicherungselemente, Dichtungselemente, Sicherungen, Batterien, Schmiernippel, Druckverschlußbeutel. Mindestbestellwert 1 Euro, Versand ab 1 Euro, Rabattstaffel bis 30%&lt;br /&gt;
&lt;br /&gt;
;Aluminium Eloxieren - http://www.electronic-thingks.de/download/index.php#1 : Anleitung (runterscrollen, PDF &amp;quot;A-1 - Eloxieren von Aluminium&amp;quot;) 307 KB runterladen.Lesenswert! Alle benötigten Farben u. Zubehör im Shop&lt;br /&gt;
&lt;br /&gt;
'''Voltmaster''' '''- http://www.voltmaster.de''' :&lt;br /&gt;
Modellbaushop, Kugel- und Gabelgelenke&lt;br /&gt;
&lt;br /&gt;
==Roboterboards==&lt;br /&gt;
;Robotik-Teile.de - http://www.robotik-teile.de: Verschiedene Roboterboards, Motor-Controllerboards, etc. Versandkosten pauschal: 4,90 € &lt;br /&gt;
&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Roboterboards, universelle Microcontrollerboards, Sprachboards, Bausätze, Platinen, Schrittmotoren, Sensoren etc. Berücksichtigt [[RN-Definitionen]]&lt;br /&gt;
&lt;br /&gt;
;Krause-Robotik - http://krause-robotik.de/Shop: einige Mikrocontrollerboards&lt;br /&gt;
&lt;br /&gt;
;PhysicalComputing - [http://physicalcomputing.at/shop/catalog/browse?sessid=THRRUckuwLLjVHbs8mUdmyO6XIdz154EyCCW5lxpo0T306pK4ppxBztdrTySkAY9&amp;amp;shop_param= http://physicalcomputing.at/shop]: Boards, Shields, Displays, LilyPad, Kit's [ideal für Einmsteiger], Sensoren, Antriebe, Elektronische Bauteile, Bücher &amp;amp; Wireless-Stuff. Österreichischer Anbieter&lt;br /&gt;
&lt;br /&gt;
==Schnittstellen und Module für Mikrocontroller==&lt;br /&gt;
&lt;br /&gt;
===LAN-Module===&lt;br /&gt;
;Wiznet WIZ812MJ Ethernet Modul - http://www.shop.display3000.com/elektronikmodule/index.html: handliche Ethernet-Modul, 3,3 bis 5 Volt&lt;br /&gt;
;ENC28J60-H  - http://olimex.com/dev/index.html: Lieferung aus Bulgarien, sehr klein&lt;br /&gt;
;Z-LAN - http://rz-robotics.de/z-lan.html: braucht nur 5V Versorgungspannung, da 3,3V-Spannungsregler onboard&lt;br /&gt;
&lt;br /&gt;
===Funkmodule===&lt;br /&gt;
;RFM12 -  http://www.pollin.de : Preisgüstiges Funkmodul ohne Eigenintelligenz, bei Pollin gibt es auch ein passendes &amp;quot;Funk-AVR-Evaluations-Board&amp;quot;&lt;br /&gt;
;XTR-7020A-8 - http://www.conrad.de: (Artikel: 191215-62), hat RS232-Schnittstelle zur Ansteuerung&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: mehrere Funkmodule u.a. EasyRadio und RT868FM mit mehreren Kanälen. Sowie passende Controllerboards und PC-Anbindungen. Berücksichtigt [[RN-Definitionen]]&lt;br /&gt;
;Avisaro WLAN Modul 2.0 -  http://shop.avisaro.com/ : WLAN Modul mit RS232, CAN, SPI oder I2C Schnittstelle (TTL Pegel). Ethernet optional.&lt;br /&gt;
&lt;br /&gt;
===Kameramodul===&lt;br /&gt;
;Artikel 150001-62 - http://www.conrad.de: Schwarz-Weiß Kamera für 5V Versorgungsspannung&lt;br /&gt;
&lt;br /&gt;
===USB-Host===&lt;br /&gt;
;STI 100 - http://www.elv.de/output/controller.aspx?cid=74&amp;amp;detail=10&amp;amp;detail2=20659:  &lt;br /&gt;
;Z-USB - http://rz-robotics.de/z-usb.html: hat auch andere Module im Angebot&lt;br /&gt;
;VDIP1 - http://www.vinculum.com/prd_vdip1.html: Demoboard von FTDI&lt;br /&gt;
&lt;br /&gt;
===Lasermodul===&lt;br /&gt;
;Artikel 158550-62 - http://www.conrad.de: Lasermodul mit 3V Versorgungsspannung und 30mA Stromverbrauch&lt;br /&gt;
&lt;br /&gt;
===Voice-Modul===&lt;br /&gt;
;Artikel 130017-62 - http://www.conrad.de: Sprachaufzeichnungsmodul mit 20 Sekunden Aufnahmedauer&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Bietet RN-Speak an. Mehrere Minuten Sprachaufzeichnung wobei einzelne Abschnitte/Sätze und Wörter per Controller angesteuert und ausgesprochen werden&lt;br /&gt;
&lt;br /&gt;
==Starterkits und universelle Mikrocontrollerboards==&lt;br /&gt;
;Thinkembedded Webshop - http://thinkembedded.ch/: Starter Kits, Evaluations Boards, Programmer, Debugger zu AVR, ARM Cortex A und Cortex M (EnergyMicro, ST, NXP), PIC, MSP430 Mikrocontrollern von div. Herstellern (Olimex, ETT, ST, ARM-Keil)&lt;br /&gt;
;Siebert-Industrie - http://shop.siebert-industrie.de: Schrittmotoren, Steuerungen, Logik-Controller, antriebstechnische Komponenten und Baugruppen für die Automatisierung. Bauteile auch für Extrembedingungen (Weltraum, Vakuum, Reinraum, Temperaturen)&lt;br /&gt;
;brazer.net - http://www.brazer.net: Roboter- und Elektronikbausätze&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Diverse Microcontrollerboards und Module(auch mit Funkmodul) für Einsteiger und Fortgeschrittene. Vom ATmega8, Atmega168, ATmega32, ATmega128 bis Mega2560. Bausätze, Platinen, Fertigmodule. Berückichtigt [[RN-Definitionen]] und sind somit kompatibel untereinander. Zubehör etc.&lt;br /&gt;
;Mikrocontrollernet Shop - http://shop.mikrocontroller.net/: verschiedene AVR Microcontrollerboards, Bausätze, Zubehör &lt;br /&gt;
;myAVR - http://www.myAVR.de: AVR Microcontrollerboards, Bausätze, Zubehör&lt;br /&gt;
;Elektronikladen - http://elmicro.com/de/index.html: Evaluation Boards, Starter Kits, Controller Module &amp;amp; Software, Programmiergeräte &amp;amp; Tools, Robotik u.v.a.m.&lt;br /&gt;
;C-Control - http://www.c-control.de: Evaluation Boards, Starter Kits, Controller Module &amp;amp; Software, Programmiergeräte &amp;amp; Tools, Robotik&lt;br /&gt;
;ELO - http://www.elo-web.de: Einsteiger Lernpakete, Software&lt;br /&gt;
;Franzis - http://www.franzis.de: Einsteiger Lernpakete, Elektronik und Computer Bücher, Software&lt;br /&gt;
&lt;br /&gt;
==CNC Protalfräsen Bausätze und Zubehör==&lt;br /&gt;
;EMS-Möderl CNC - http://www.mixware.de: CNC Hardware, Spindeln, Profile, Antriebe, Bausätze, '''Forum'''&lt;br /&gt;
&lt;br /&gt;
=Sonstiges=&lt;br /&gt;
;http://shop.lipopower.de: Schutzschaltungen für Li-Po und Li-Ion Akkus&lt;br /&gt;
;http://www.ebay.de: Möglicherweise alles was in o.g. Links nicht erhältlich ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Bezugsquellen&amp;diff=21399</id>
		<title>Bezugsquellen</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Bezugsquellen&amp;diff=21399"/>
				<updated>2012-10-26T11:14:58Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| {{Blaueschmaltabelle}}&lt;br /&gt;
|Hier können Bezugsquellen eingetragen werden! Bitte aber pro Eintrag nicht mehr als '''2 bis 3 Zeilen''', ansonsten muss es ein Moderator kürzen! Dieser Artikel soll nicht als Werbeplattform mißbraucht werden, für Werbung gibts andere [[RN-Wissen:Site_support|Möglichkeiten]]. Er soll eine Hilfe für Bastler sein. '''Daher sollen hier auch nur Firmen eingetragen werden, welche eine Bestellmöglichkeit Webformular oder Online-Shop bereitstellen'''.&lt;br /&gt;
Bitte auch keine Bewertungen der Lieferanten vornehmen, das ist Sache der Leser &amp;amp; Bastler indem Sie vergleichen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Elektronikbauteile==&lt;br /&gt;
&lt;br /&gt;
;Rehag - http://www.rehag.de: Optoelektronische Bauteile für Groß- und Kleinkunden.&lt;br /&gt;
&lt;br /&gt;
;Conrad - http://www.conrad.de: Fast alle Standardelektronikbauteile&lt;br /&gt;
&lt;br /&gt;
;CSD-Electronic - http://www.csd-electronics.de/: Elektronik&lt;br /&gt;
&lt;br /&gt;
;Digi-Key Corporation - http://de.digikey.com/: Diverse Bauelemente, Microcontroller, Sensoren, auch 'exotische' Bauteile, sehr umfangreiches Sortiment, kostenloser Katalog, Suchfunktion nach Parametern&lt;br /&gt;
&lt;br /&gt;
;Distrelec Gruppe - http://www.distrelec.com: Ableger in vielen Ländern, Diverse Bauelemente (aktiv, passiv, Microcontroller), Literatur, PC-Komponenten, usw.&lt;br /&gt;
&lt;br /&gt;
;Farnell In One - http://de.farnell.com/: elektronische Bauelemente (aktiv, passiv, Microcontroller), Sensoren, Literatur, Entwicklungskits, Kabel, Steckverbinder, Werkstattbedarf. Beliefert nur (bel.) angemeldete '''Gewerbe und Stud.''' (mit Nachweis) Nicht für privat. Sehr schnell. Sehr gut Sortiert (auch &amp;quot;exotische&amp;quot; Bauelemente)&lt;br /&gt;
&lt;br /&gt;
;HBE-Shop Farnell auch für Privat - http://www.hbe-shop.de: HBE Fachhändler für FARNELL, Ab einem Warenwert von 50,00 € (netto) Standardpakete versandkostenfrei.&lt;br /&gt;
&lt;br /&gt;
;Robotik-Teile.de - http://www.robotik-teile.de: Aktive und Passive Bauelemente, Microcontroller, Controllerboards, etc. Versandkosten pauschal: 4,90 €&lt;br /&gt;
&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Microcontroller, spezielle Controller und einige schwer erhältliche Bauteile (auch SMD)&lt;br /&gt;
&lt;br /&gt;
;Kessler-Electronic - http://www.kessler-electronic.de/: ( ehemals Simons ) Diverse Bauelemente (aktiv, passiv, Microcontroller), Literatur, PC-Komponenten, Messgeräte, Hifi, usw. Preisstaffelung für größere Mengen, Mindestbestellwert: 10 Euro&lt;br /&gt;
&lt;br /&gt;
;marsch-elektronik - http://www.marsch-elektronik.de/: Diverse Bauelemente (aktiv, passiv, Mikrocontroller, LEDs), kein Mindestbestellwert, niedrige Versandkosten (ab 40 Euro versandkostenfrei). Es werden auch sogenannte &amp;quot;Einsteigersortimente&amp;quot; und Widerstandssortimente (auch SMD) angeboten. Nicht gelistete Bauelemente können angefragt werden.&lt;br /&gt;
&lt;br /&gt;
;Neuhold Electronik - http://www.neuhold-elektronik.at: Restposten&lt;br /&gt;
&lt;br /&gt;
;no DNA - http://www.nodna.com/: Diverse Roboterbauteile, Sensoren und komplette Roboter; keine Bauelemente wie Widerstände, Transistoren etc. Viel Zubehör vom amerikanischen Markt. Keine Mindestbestellmenge.&lt;br /&gt;
&lt;br /&gt;
;Pollin Electronic - http://www.pollin.de/: Diverse Bauelemente und Sortimente zu Spottpreisen, fast alles Restposten oder Gebrauchte Teile, daher kein beständiges Sortiment&lt;br /&gt;
&lt;br /&gt;
;Reichelt - http://www.reichelt.de: Diverse Bauelemente (aktiv, passiv, Microcontroller), Literatur, PC-Komponenten, Lichttechnik, Messtechnik, Software,  Kabel, Steckverbinder, Werkstattbedarf, Werkzeug,  Mindestbestellwert: 10 Euro&lt;br /&gt;
&lt;br /&gt;
;RS-Components - http://www.rsonline.de: Bauelemente: (aktiv, passiv, Microcontroller), Literatur, PC-Komponenten, Lichttechnik, Messtechnik, Software, Kabel, Steckverbinder, Werkzeug&lt;br /&gt;
&lt;br /&gt;
;Ribu Elektronik - http://www.ribu.at: Diverse Bauelemente, ICs, österreichische Seite&lt;br /&gt;
&lt;br /&gt;
;guloshop.de - http://guloshop.de: nur wenige Standard-Mikrocontroller, diese aber zu sehr niedrigen Preisen (Mikrocontroller-Discounter). Versandkosten bei Bestellungen bis 10 Euro: 2,40 Euro, sonst 4,40 Euro.&lt;br /&gt;
&lt;br /&gt;
==Sensoren==&lt;br /&gt;
&lt;br /&gt;
;Robotik-Teile.de - http://www.robotik-teile.de: Beschleunigungssensoren, Gyros &amp;amp; Komapsse, Gas-Sensoren, Infrarotsensoren, Stromsensoren und Ultraschallsensoren. Versandkosten pauschal: 4,90 €&lt;br /&gt;
&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Drehgeber, Sharp-Entfernungssensoren, Ultraschallsensoren, Neigungssensoren, Temperatursensoren, Hallsensoren, Beschleunigungssensoren Magnete usw. speziell für Robotik-Bastler&lt;br /&gt;
&lt;br /&gt;
;MANU SYSTEMS - http://de.manu-systems.com/ROBOT_ELECTRONICS.shtml: Ultraschallsensoren, Kompassmodule, Temperatursensor Array&lt;br /&gt;
&lt;br /&gt;
;Micromaus - http://www.micromaus.de: Sharp-Entfernungssensoren, Farbsensoren, Feuchtesensoren, Flexsensoren, Beschleunigungssensoren, Drucksensoren usw.&lt;br /&gt;
&lt;br /&gt;
;Roboter-Teile - http://www.roboter-teile.de/ : Lynxmotion Hexapot, Sensoren, CMU-Cam, AVR, PIC u.v.a.&lt;br /&gt;
&lt;br /&gt;
;Conrad - http://www.conrad.de: Fast alle Standardelektronikbauteile&lt;br /&gt;
&lt;br /&gt;
;Digi-Key Corporation - http://de.digikey.com/: Diverse Bauelemente, Microcontroller, Sensoren, auch 'exotische' Bauteile, sehr umfangreiches Sortiment, kostenloser Katalog. Hohe Versandkosten (über 30 Euro selbst bei Kleinteilen)&lt;br /&gt;
&lt;br /&gt;
;Krause Robotik - http://www.krause-robotik.de/Shop/: Diverse Sensoren und Mikrocontrollerboards. 4,65 € Versand&lt;br /&gt;
&lt;br /&gt;
;austriamicrosystems - http://www.austriamicrosystems.com/: Winkelencoder auf magnetischer Hallbasis, diverse analoge Komponenten, bsp. A/D converter, LDOs, Watchdog, I/O Expanderchips. Muster und kleine Stückzahlen koennen direkt ueber https://shop.austriamicrosystems.com/ bestellt werden.&lt;br /&gt;
&lt;br /&gt;
;WayCon Positionsmesstechnik - http://www.waycon.de : Seilzugsensor, Induktiver Sensor LVDT, Wirbelstrom, Lasersensor, Digitales Magnetband, Digitaler Messtaster, Digitaler Maßstab, Linearpotentiometer, Magnetostriktive Geber, Ultraschall, Anzeigen u Displays, Endocder u Winkelgeber&lt;br /&gt;
&lt;br /&gt;
==Motoren und Schrittmotoren== &lt;br /&gt;
;Siebert-Industrie - http://shop.siebert-industrie.de: Schrittmotoren, Steuerungen, Logik-Controller, antriebstechnische Komponenten und Baugruppen für die Automatisierung. Bauteile auch für Extrembedingungen (Weltraum, Vakuum, Reinraum, Temperaturen)&lt;br /&gt;
&lt;br /&gt;
;mir-elektronik - http://www.mir-elektronik.de: Schrittmotoren, Endstufen, Bauteile, Literatur und Sonderposten&lt;br /&gt;
;Lemo-Solar - http://lemo-solar.de/: Motoren, Getriebe, Elektronik-Bausätze, Sonderposten u.v.a.&lt;br /&gt;
&lt;br /&gt;
;Robotik-Teile.de - http://www.robotik-teile.de: Metall-Getriebemotoren, Plastik-Getriebemotoren, Schrittmotoren, Servos, Solarbotics Getriebe und Tamiya Motoren und Getriebe. Versandkosten pauschal: 4,90 €&lt;br /&gt;
&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Schrittmotor-Angebote, Tamiya Modellbau Getriebemotoren, Devantech Getriebemotoren mit eingebauten Drehgeber&lt;br /&gt;
&lt;br /&gt;
;Conrad - http://www.conrad.de: Fast alle Standardelektronikbauteile&lt;br /&gt;
&lt;br /&gt;
;Nanotec - http://www.nanotec.de: Schrittmotoren für Industrieeinsatz, aber Einzelabnahme möglich&lt;br /&gt;
&lt;br /&gt;
;seacontrol - http://www.seacontrol.de: Ist komischerweise ein Aquaristikshop, hat aber auch Schrittmotoren (aus der eigenen Entwicklungsapteilung, oder so) von der Startseite in den online-shop, im shop unten links findet mann die Motoren&lt;br /&gt;
&lt;br /&gt;
;Farnell In One - http://de.farnell.com/: elektronische Bauelemente (aktiv, passiv, Microcontroller), Motoren, Schrittmotoren, Linearmotoren, Sensoren, Literatur, Entwicklungskits, Kabel, Steckverbinder, Werkstattbedarf. Beliefert nur (bel.) angemeldete '''Gewerbe und Stud'''. (mit Nachweis) Nicht für privat. Sehr schnell. Sehr gut Sortiert (auch &amp;quot;exotische&amp;quot; Bauelemente)&lt;br /&gt;
&lt;br /&gt;
==Platinen==&lt;br /&gt;
&lt;br /&gt;
;Multi PCB Ltd. - Leiterplatten - http://www.multipcb.de: Leiterplatten-Discount mit 1-48 Lagen im Online-Kalkulator. Ab 48h Express. Service nur für gewerbliche Kunden.&lt;br /&gt;
&lt;br /&gt;
;PCB-Pool - http://pcb-pool.com: Platinenservice für private und gewerbliche Kunden.&lt;br /&gt;
&lt;br /&gt;
;ANDUS ELECTRONIC GmbH - www.andus.de http://www.andus.de: High-End Leiterplatten und Express-Prototypen in allen Technologien (Multilayer, flexible Leiterplatten, Starrflex,...). Persönliche Technologieberatung für Aufbau und Design von Leiterplatten.&lt;br /&gt;
&lt;br /&gt;
;Robotikhardware.de - http://www.robotikhardware.de: Preiswerte Standard Platinen (beste Industriequalität mit E-Prüfung) zu sehr vielen Robotik- und Microcontrollerschaltungen, inkl. Bauanleitung und Beispielprogrammen.&lt;br /&gt;
&lt;br /&gt;
;LeitOn GmbH - www.leiton.de - http://www.leiton.de: Leiterplatten sofort online kalkulieren und bestellen. Expressdienste von 1 bis 10 Lagen Multilayer in deutscher Industriequalität. Flexible Leiterplatten online kalkulieren. Für Privat und Firmen! Ab 12h.&lt;br /&gt;
&lt;br /&gt;
;Top Tec PCB Ltd. - http://www.top-tec-pcb.de: Günstige Leiterplatten vom Prototyp bis zur Groß-Serie. Viele High-Tech-Optionen sind schon Inklusive.&lt;br /&gt;
&lt;br /&gt;
;Basista Leiterplatten GmbH - http://www.basista.de: Leiterplatten ab 8 Stunden Express-Service. RoHS-konforme Profi-Qualität, mit Onlinekalkulation. Für private und gewerbliche Kunden.&lt;br /&gt;
&lt;br /&gt;
;LFG Oertel - http://www.lfg-oertel.de: Leiterplattenherstellung und Bestückung aus einer Hand. Fertigung und Bestückung ab 1 Stück. Für gewerbliche Kunden.&lt;br /&gt;
&lt;br /&gt;
;GLS Leiterplatten-Service GmbH - http://www.leiterplattenprototypen.de: Prototypenfertigung für Leiterplatten bei Chemnitz bietet zusätzlich viele Serviceleistungen rund um die Leiterplatte (z.B. Scannen/Digitalisieren von Leiterplatten und Leiterplattenlayouts)&lt;br /&gt;
&lt;br /&gt;
;D-E-K Dischereit - http://www.dischereit.de: Preiswerter Komplettservice für die Leiterplattenbestückung von Prototypen und Kleinserien.&lt;br /&gt;
&lt;br /&gt;
;pcb-joker - http://www.pcb-joker.com: Leiterplatten sofort online kalkulieren und bestellen. Von 1 bis 4 Lagen Multilayer. Für Privat und Firmen!&lt;br /&gt;
&lt;br /&gt;
==Anzeigen / LCD's==&lt;br /&gt;
;Display3000 - http://www.shop.display3000.de: Farbdisplays, TFTs, Touchscreens, Mikrocontrollermodule&lt;br /&gt;
&lt;br /&gt;
;Siebert-Industrie - http://shop.siebert-industrie.de: Schrittmotoren, Steuerungen, Logik-Controller, antriebstechnische Komponenten und Baugruppen für die Automatisierung. Bauteile auch für Extrembedingungen (Weltraum, Vakuum, Reinraum, Temperaturen)&lt;br /&gt;
&lt;br /&gt;
;IbS Sperling - http://www.ibs-display.de: LCD-Module, Grafik-LCD, TouchScreens&lt;br /&gt;
&lt;br /&gt;
;Conrad - http://www.conrad.de: Fast alle Standardelektronikbauteile&lt;br /&gt;
&lt;br /&gt;
;Electronic Assembly - http://www.lcdmodule.de: LCD-Module, Grafik-LCD, dog&lt;br /&gt;
&lt;br /&gt;
;LEDsee - http://www.ledsee.com: LED's, Lumeon, LCD's Grafik-LCD, pLED, oLED, Zubehör (Direktversand aus Japan, relativ schnell ca. 1 Woche)&lt;br /&gt;
&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Verschiedene LCD´s sowie Adapter zum Anschluss an Boards nach Roboternetz-Definition (passend zu [[RN-Control]], [[RN-MiniControl]] usw.)&lt;br /&gt;
&lt;br /&gt;
==Materialien==&lt;br /&gt;
;TECHNOPLAST - http://www.technoplast-onlineshop.de/: Technische Kunststoff Halbzeuge Polycarbonat Platten Plexiglas Acrylglas Rundstäbe Rohre ...&lt;br /&gt;
&lt;br /&gt;
;Opitec - http://www.opitec.de/: Elektromotoren, zahlreiche Zahnräder, Werkzeuge, Räder, diverse Materialien (Kunststoff, Gummi, Papier, Pappe, Holz, Metall, Textilien, Plexiglas ...)&lt;br /&gt;
&lt;br /&gt;
;Metall Store - http://www.metallstore.de/: Schrittmotoren, (Kugel-)Lager, diverse Bauelemente aus Alu, VA, Messing, Bronze, Kupfer, Werkzeuge, Spezialschrauben&lt;br /&gt;
&lt;br /&gt;
;Modulor - http://www.modulor.de/: Diverse Materialien Kunststoff, Gummi, Papier, Pappe, Holz, Metall, Textilien, Plexiglas ...&lt;br /&gt;
&lt;br /&gt;
;Igus - http://www.igus.de/: Gleitlager, Lineargleitlager, Kabelschleppen, Gelenklager, Polymergleitlager, Wellen ...&lt;br /&gt;
&lt;br /&gt;
;Kienzle Plexiglas - http://www.ernst-kienzle.de/: Acrylglas, Polycarbonat, Polyethylenterephtalatglycol (in vielen Farben, auch Formen machbar)&lt;br /&gt;
&lt;br /&gt;
;Maedler - http://www.maedler.de/: Antriebselemente und Normteile, Getriebe und Getriebemotoren, Pneumatikelemente, Zahnriemen, Zahnriemenräder, div. Lager ...&lt;br /&gt;
&lt;br /&gt;
;Octamex - http://www.octamex.de/: Leiterplatten (in versch. Dicken), Chemikalien zum Ätzen und Veredeln, Elektronikbauteile, Lötstop- und Bestückungsdruck-Laminate, Gehäusetechnik&lt;br /&gt;
&lt;br /&gt;
;Lelebeck - http://www.lelebeck.de/index.htm : Verbindungselemente, Mech. Sicherungselemente, Dichtungselemente, Sicherungen, Batterien, Schmiernippel, Druckverschlußbeutel. Mindestbestellwert 1 Euro, Versand ab 1 Euro, Rabattstaffel bis 30%&lt;br /&gt;
&lt;br /&gt;
;Aluminium Eloxieren - http://www.electronic-thingks.de/download/index.php#1 : Anleitung (runterscrollen, PDF &amp;quot;A-1 - Eloxieren von Aluminium&amp;quot;) 307 KB runterladen.Lesenswert! Alle benötigten Farben u. Zubehör im Shop&lt;br /&gt;
&lt;br /&gt;
'''Voltmaster''' '''- http://www.voltmaster.de''' :&lt;br /&gt;
Modellbaushop, Kugel- und Gabelgelenke&lt;br /&gt;
&lt;br /&gt;
==Roboterboards==&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Roboterboards, universelle Microcontrollerboards, Sprachboards, Bausätze, Platinen, Schrittmotoren, Sensoren etc. Berücksichtigt [[RN-Definitionen]]&lt;br /&gt;
&lt;br /&gt;
;Krause-Robotik - http://krause-robotik.de/Shop: einige Mikrocontrollerboards&lt;br /&gt;
&lt;br /&gt;
;PhysicalComputing - [http://physicalcomputing.at/shop/catalog/browse?sessid=THRRUckuwLLjVHbs8mUdmyO6XIdz154EyCCW5lxpo0T306pK4ppxBztdrTySkAY9&amp;amp;shop_param= http://physicalcomputing.at/shop]: Boards, Shields, Displays, LilyPad, Kit's [ideal für Einmsteiger], Sensoren, Antriebe, Elektronische Bauteile, Bücher &amp;amp; Wireless-Stuff. Österreichischer Anbieter&lt;br /&gt;
&lt;br /&gt;
==Schnittstellen und Module für Mikrocontroller==&lt;br /&gt;
&lt;br /&gt;
===LAN-Module===&lt;br /&gt;
;Wiznet WIZ812MJ Ethernet Modul - http://www.shop.display3000.com/elektronikmodule/index.html: handliche Ethernet-Modul, 3,3 bis 5 Volt&lt;br /&gt;
;ENC28J60-H  - http://olimex.com/dev/index.html: Lieferung aus Bulgarien, sehr klein&lt;br /&gt;
;Z-LAN - http://rz-robotics.de/z-lan.html: braucht nur 5V Versorgungspannung, da 3,3V-Spannungsregler onboard&lt;br /&gt;
&lt;br /&gt;
===Funkmodule===&lt;br /&gt;
;RFM12 -  http://www.pollin.de : Preisgüstiges Funkmodul ohne Eigenintelligenz, bei Pollin gibt es auch ein passendes &amp;quot;Funk-AVR-Evaluations-Board&amp;quot;&lt;br /&gt;
;XTR-7020A-8 - http://www.conrad.de: (Artikel: 191215-62), hat RS232-Schnittstelle zur Ansteuerung&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: mehrere Funkmodule u.a. EasyRadio und RT868FM mit mehreren Kanälen. Sowie passende Controllerboards und PC-Anbindungen. Berücksichtigt [[RN-Definitionen]]&lt;br /&gt;
;Avisaro WLAN Modul 2.0 -  http://shop.avisaro.com/ : WLAN Modul mit RS232, CAN, SPI oder I2C Schnittstelle (TTL Pegel). Ethernet optional.&lt;br /&gt;
&lt;br /&gt;
===Kameramodul===&lt;br /&gt;
;Artikel 150001-62 - http://www.conrad.de: Schwarz-Weiß Kamera für 5V Versorgungsspannung&lt;br /&gt;
&lt;br /&gt;
===USB-Host===&lt;br /&gt;
;STI 100 - http://www.elv.de/output/controller.aspx?cid=74&amp;amp;detail=10&amp;amp;detail2=20659:  &lt;br /&gt;
;Z-USB - http://rz-robotics.de/z-usb.html: hat auch andere Module im Angebot&lt;br /&gt;
;VDIP1 - http://www.vinculum.com/prd_vdip1.html: Demoboard von FTDI&lt;br /&gt;
&lt;br /&gt;
===Lasermodul===&lt;br /&gt;
;Artikel 158550-62 - http://www.conrad.de: Lasermodul mit 3V Versorgungsspannung und 30mA Stromverbrauch&lt;br /&gt;
&lt;br /&gt;
===Voice-Modul===&lt;br /&gt;
;Artikel 130017-62 - http://www.conrad.de: Sprachaufzeichnungsmodul mit 20 Sekunden Aufnahmedauer&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Bietet RN-Speak an. Mehrere Minuten Sprachaufzeichnung wobei einzelne Abschnitte/Sätze und Wörter per Controller angesteuert und ausgesprochen werden&lt;br /&gt;
&lt;br /&gt;
==Starterkits und universelle Mikrocontrollerboards==&lt;br /&gt;
;Thinkembedded Webshop - http://thinkembedded.ch/: Starter Kits, Evaluations Boards, Programmer, Debugger zu AVR, ARM Cortex A und Cortex M (EnergyMicro, ST, NXP), PIC, MSP430 Mikrocontrollern von div. Herstellern (Olimex, ETT, ST, ARM-Keil)&lt;br /&gt;
;Siebert-Industrie - http://shop.siebert-industrie.de: Schrittmotoren, Steuerungen, Logik-Controller, antriebstechnische Komponenten und Baugruppen für die Automatisierung. Bauteile auch für Extrembedingungen (Weltraum, Vakuum, Reinraum, Temperaturen)&lt;br /&gt;
;brazer.net - http://www.brazer.net: Roboter- und Elektronikbausätze&lt;br /&gt;
;Robotikhardware - http://www.robotikhardware.de: Diverse Microcontrollerboards und Module(auch mit Funkmodul) für Einsteiger und Fortgeschrittene. Vom ATmega8, Atmega168, ATmega32, ATmega128 bis Mega2560. Bausätze, Platinen, Fertigmodule. Berückichtigt [[RN-Definitionen]] und sind somit kompatibel untereinander. Zubehör etc.&lt;br /&gt;
;Mikrocontrollernet Shop - http://shop.mikrocontroller.net/: verschiedene AVR Microcontrollerboards, Bausätze, Zubehör &lt;br /&gt;
;myAVR - http://www.myAVR.de: AVR Microcontrollerboards, Bausätze, Zubehör&lt;br /&gt;
;Elektronikladen - http://elmicro.com/de/index.html: Evaluation Boards, Starter Kits, Controller Module &amp;amp; Software, Programmiergeräte &amp;amp; Tools, Robotik u.v.a.m.&lt;br /&gt;
;C-Control - http://www.c-control.de: Evaluation Boards, Starter Kits, Controller Module &amp;amp; Software, Programmiergeräte &amp;amp; Tools, Robotik&lt;br /&gt;
;ELO - http://www.elo-web.de: Einsteiger Lernpakete, Software&lt;br /&gt;
;Franzis - http://www.franzis.de: Einsteiger Lernpakete, Elektronik und Computer Bücher, Software&lt;br /&gt;
&lt;br /&gt;
==CNC Protalfräsen Bausätze und Zubehör==&lt;br /&gt;
;EMS-Möderl CNC - http://www.mixware.de: CNC Hardware, Spindeln, Profile, Antriebe, Bausätze, '''Forum'''&lt;br /&gt;
&lt;br /&gt;
=Sonstiges=&lt;br /&gt;
;http://www.ebay.de : möglicherweise alles was in o.g. Links nicht erhältlich ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=21093</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=21093"/>
				<updated>2012-09-20T15:55:25Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Hilfsmittel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich. Bei PIC's ist echtes Multitasking (Parallellaufen) nur mit Timer und ADC Wandler möglich (siehe dazu: http://www.roboternetz.de/community/threads/42200-Frequenzz%C3%A4hler-mit-LPH2673-1-%28zum-Nachbauen%29?highlight=LPH2673-1 ) &lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende realisiert. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer unterbrochen und nächster Tast gestartet. Dafür muss immer nach Beenden der ISR unbedingt ins HP gesprungen werden und die Adresse vom PC, wo der Task unterbrochen wurde auf dem Stapel gespeichert werden. Wenn die Zeit für den unterbrochenen Task wieder kommt, wird er ab der unterbrochenen Stelle wieder in der ihn zustehenden Zeit ausgeführt, wieder unterbrochen u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
Hoffentlich hilfreiche Beiträge sind auch dort zu finden: http://www.roboternetz.de/community/threads/26098-Tips-Tricks .&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Sensoren&amp;diff=20631</id>
		<title>Sensoren</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Sensoren&amp;diff=20631"/>
				<updated>2012-08-22T13:43:34Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Direkte Sensoren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Sensoren==&lt;br /&gt;
Jeder, der sich einen Roboter baut, wird schnell zu dem Punkt kommen, wo er möchte, dass sein Roboter „sieht“. &lt;br /&gt;
Sensoren müssen hauptsächlich drei Aufgaben erledigen. Die ersten beiden sind Kollisionsschutz und Navigation. Diese unterscheiden sich in der Funktionsweise vor allem in der Interpretation, im Programm und im Aufbau am Roboter. Die dritte Art sind Sensoren, die ihn mit der Umwelt in Kontakt treten lassen. &lt;br /&gt;
&lt;br /&gt;
Grundsätzlich müssen alle Sensoren diese Merkmale aufweisen: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Passiv oder aktiv?=== &lt;br /&gt;
Manche Sensoren (z.B. IR) brauchen eine aktive Quelle (hier die IR-LED), die dann aber einen Mehrverbrauch an Strom bedeutet. Passive Sensoren, wie zB Taster, bekommen ihre Signale aus der Umwelt (hier Stoß). Zu ihnen zählen die meisten Umweltgrößen, wie Temperatur und Feuchtigkeit, Licht und Vibration oder Kraft (Stoß). &lt;br /&gt;
&lt;br /&gt;
===Einfachheit===&lt;br /&gt;
Ein Sensor muss einfach sein. Denn was nützt es uns, wenn wir den Sensor nicht kalibrieren können oder der Aufbau zu schwer ist? Doch Sensoren, die nicht in einem einzigen Gehäuse untergebracht sind, sind äußerst selten. Dann besteht nur noch der Wunsch, dass die meist zweidrahtigen Sensoren auch einfach anzuschließen sind. Deswegen ist es manchmal von Vorteil, sich vorgefertigte Anschlüsse zu kaufen, anstatt diese in mühsamer Kleinarbeit selber zu erstellen. &lt;br /&gt;
&lt;br /&gt;
===Auswertbarkeit in Echtzeit===&lt;br /&gt;
Alle Sensoren, die zunächst in Frage kommen, basieren auf dem Prinzip des Spannungsteilers. Das heißt, es wird eine Urspannung eingegeben und eine Teilspannung kommt heraus. Diese Differenz können wir erfassen und mittels Wertetabelle im Programm auswerten. Aber durch Störeinflüsse in der Umwelt kann es vorkommen, dass die berechneten Werte abweichen. Jeder Messtechniker weiß, dass allein die Messung an sich schon das Messergebnis verfälscht.&lt;br /&gt;
&lt;br /&gt;
===Robustheit===&lt;br /&gt;
Wir werden am Anfang sicher nicht unseren Roboter in einer Morastlandschaft einsetzen, aber auch schon ein Stoß gegen die Wand hat manchen Roboter ausgeknockt. Schon normaler Hausstaub kann und wird Linsen trüben und Messwerte verschlechtern. Das heisst: Wenn ein Sensor gekauft wird, muss er der Situation angemessen sein.&lt;br /&gt;
&lt;br /&gt;
==Aufgaben für Roboter==&lt;br /&gt;
Natürlich muss man sich, bevor der Roboter steht, schon im Klaren sein, was seine Aufgaben sind. Auch wenn diese so weitgefasst sind wie „Karte erstellen – Raumüberwachung – dabei einer Linie folgen“. Jeder Sensor braucht Platz und verringert die Einsatzdauer. Nicht jeder Sensor ist für jede Arbeit gedacht und zum Schluss spielt das Geld eine Rolle, denn mancher Sensor kostet schon 30 Euro. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sensoren für den Kollisionsschutz===&lt;br /&gt;
Die wichtigsten Sensoren auf einem Roboter sind die Kollisionssensoren. Diese schützen den Roboter vor Zusammenstößen und Abstürzen in einen Schacht. Dabei kann man diese Gruppe in direkte und indirekte Sensoren unterteilen. &lt;br /&gt;
&lt;br /&gt;
====Direkte Sensoren====&lt;br /&gt;
Sie sollen den Zusammenstoß nicht verhindern, sondern dabei das Signal ausgeben. In letzter Zeit werden diese Sensoren noch gepolstert, damit beim Zusammenstoß keine zu großen Kräfte auftreten. &lt;br /&gt;
Am Einfachsten geht dies mit einem Taster, der am Chassis befestigt ist. Da dies sehr kurze Reaktionszeiten mit sich bringt, haben einige Roboter Fühler, um diese Zeit zu verlängern. Eine weitere Methode ist es, eine Stoßstange zu entwickeln, die dann an den Tastern (direkt oder indirekt) befestigt wird. Dabei kann diese Stoßstange auch gepolstert sein. Eine nun neuere Methode ist es, Luftschläuche zu verwenden. Die dämpfen den Stoß ab und sind dabei an einem Drucksensor angeschlossen, der das Zusammenquetschen erkennt und ein Signal ausgibt.&lt;br /&gt;
&lt;br /&gt;
Als Taster kann auch ein virtueller Bumper verwendet werden. Das Prinzip ist, eine Stromerhöhung eines Antriebsmotors beim Kollidieren mit einem Hindernis als Bumper zu emulieren. Das ermöglicht praktisch einen Roboter so zu steuern, wie wenn auf seinem ganzen Umfang echte Bumpers befestigt wären. Beim Kollidieren mit einem Hindernis wird der Ausgang der Schaltung (siehe Skizze) mit dem GND kurzgeschlossen, genauso wie wenn ein echter Bumper betätigt wäre. Hardware- bzw softwaremäßig kann man den Wirkungsbereich des virtuellen Bumpers nach individuellen Wünschen gestalten (siehe eventuell dazu: http://www.roboternetz.de/community/threads/55075-Selbstsau ).&lt;br /&gt;
&lt;br /&gt;
Der Spannungsabfall auf dem Shunt (Rs) sollte bei normalem Fahren sicher unter der Spannung liegen, die der Transistor (T) zum Leiten braucht (ca. 0,7 V für normale und ca. 1,4 V für Darlington-Transistoren), z.B. 0,4 V. Bei Kollision mit einem Hindernis sollte der Spannungsabfall auf dem Rs sicher die o.g. Spannung überschreiten und z.B. 0,8 V oder höher sein. Der Elko (C) verzögert den Anstieg der Spannung auf dem Rs für den Anlaufstrom des Motors, der bis ca. 5-fach größer als beim unbehinderten Fahren ist. Für einen konkreten Motor und µC müssen die Rs, Rp (eventuell innerer pull-up) und C entsprechend angepasst werden, damit die Schaltung zufriedenstellend funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Beispielschaltung wurde fur einen DC-Getriebemotor mit folgenden Parametern entwickelt:&lt;br /&gt;
&lt;br /&gt;
- Strom beim unbehindertem Fahren: ca. 0,4 A&lt;br /&gt;
&lt;br /&gt;
- Strom beim gebremstem Motor: ca. 0,8 A&lt;br /&gt;
&lt;br /&gt;
- Anlaufstrom beim Anfahren: ca. 2 A&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                                VCC&lt;br /&gt;
                                                 +&lt;br /&gt;
                                                 |&lt;br /&gt;
                                                .-.&lt;br /&gt;
                                                | | Rp&lt;br /&gt;
                     +-----------------------+  | | 1k&lt;br /&gt;
                     |                       |  '-'&lt;br /&gt;
                     |         Rb            |   |&lt;br /&gt;
                     |                    +------+-&amp;gt; zum µC Pin&lt;br /&gt;
                     |         1k         |  |       (anstatt Bumper)&lt;br /&gt;
                     |        ___       |/   |&lt;br /&gt;
     von H-Brücke &amp;gt;--------+-|___|-+----| T  |&lt;br /&gt;
    (üblich mit GND  |     |       |    |&amp;gt;   |&lt;br /&gt;
     verbunden)      |    .-.      |+     |  |&lt;br /&gt;
                     | Rs | |     === C  === |&lt;br /&gt;
                     |    | |     /-\    GND |&lt;br /&gt;
                     |  1 '-'      | 100µ    |&lt;br /&gt;
                     |     |       |         |&lt;br /&gt;
                     |    ===     ===        |&lt;br /&gt;
                     |    GND     GND        |&lt;br /&gt;
                     |                       |&lt;br /&gt;
                     +-----------------------+&lt;br /&gt;
                         virtueller Bumper&lt;br /&gt;
&lt;br /&gt;
Als virtueller Bumper kann auch an ein Antriebsrad angebrachter Impulsgeber softwaremässig emuliert werden.&lt;br /&gt;
&lt;br /&gt;
====Indirekte Sensoren====&lt;br /&gt;
Sie sollen helfen, den Zusammenstoß zu vermeiden, um bestenfalls noch Zeit zu geben, einen optimalen Weg ums Hindernis herum zu finden. Diese haben ein größeres Problem, da sie meist keine 360-Grad-„Rundumsicht“ garantieren können. Das bedeutet, dass die meisten Roboter diesen Typ der Sensoren in Fahrtrichtung eingebaut haben, um diese Aufgabe zu erfüllen. Was auch effizient ist, denn solche Sensoren sind sehr teuer und müssen ständig vom Programm überwacht werden. &lt;br /&gt;
&lt;br /&gt;
Diese Sensoren werden bei neueren Autos auch als Parkhilfe angeboten.&lt;br /&gt;
&lt;br /&gt;
==Probleme==&lt;br /&gt;
Das Problem der Sensoren ist ihre räumliche Begrenztheit. Denn schon 5 Meter sind sehr lang. Aber auf der anderen Seite wollen die meisten ohnehin keine 5 Meter „vorausschauen“. &lt;br /&gt;
[[Sensorarten|Es gibt mehrere Typen]]. Am bekanntesten sind die [[Sensorarten#optische_Sensoren|IR-Sensoren]]. Diese sind gut für lange Distanzen, aber haben das Problem, dass sie gebündelt sind und somit Zwischenräume schwer abdecken können. Besser sind dort [[Sensorarten#Ultraschall_Sensoren|Ultraschallsensoren]], die aber teurer sind. Etwas in der Nische ist das Radar-System; es ist ein sehr aufwendiges und teueres System und die Auswertung der Daten ist komplex. Es bietet aber den besten Schutz gegen Zusammenstöße, da dieses System nicht auf einen Punkt gerichtet ist, sondern die ganze Fläche abscannt. &lt;br /&gt;
&lt;br /&gt;
Problem beider Systeme: &lt;br /&gt;
Das ist die Höhe. Leider ist unser Roboter dreidimensional und bewegt sich zweidimensional. Das heißt, es spannen sich mehrere Ebenen auf, die überwacht werden wollen. Denn wenn dies nicht geschieht, stößt der Roboter gegen eine Tischplatte, weil er diese nicht erkannt hat oder gegen ein Hindernis, das unter den Sensoren hindurch rutschte. &lt;br /&gt;
Deswegen bemüht man sich, den Roboter so flach wie möglich zu halten und das Fahrgestell so zu bauen, dass man flache Hindernisse überfahren kann. Es hilft also, sich darüber vorher Gedanken zu machen. &lt;br /&gt;
Je nachdem wo der Roboter zum Einsatz kommt tun sich manchmal Abgründe auf (z.B. Tischplatte). Diese müssen erkannt werden. Deswegen ist es erforderlich, Abstandssensoren noch unten zu richten, um einen Absturz zu vermeiden. Dabei sollte man indirekte Sensoren einsetzen, denn was nützt es, wenn der Taster erkannt hat, dass nun ein Loch da ist, aber der Roboter bis zur Reaktion schon auf dem Boden aufschlägt?&lt;br /&gt;
&lt;br /&gt;
==Navigation==&lt;br /&gt;
Nun gibt es hier viele Arten, wie die Navigation erfolgen kann. Ich tue 2 Felder auf. Wenn unser Freund neue Welten erkunden soll oder in einem Spiel gegen eine Mannschaft antritt, dann braucht er andere Sensoren, als wenn er routiniert Wege abfahren soll. Obwohl sich die Felder überschneiden. &lt;br /&gt;
&lt;br /&gt;
Alle Navigationssysteme bauen auf 2 Quellen der Navigation auf: [[Sensorarten#Drehgeber_Sharp_GP1A30|inkrementale Weggeber]] und Absolutwertgeber. &lt;br /&gt;
&lt;br /&gt;
Dies ist das größte Problem, wenn ihr einen Bot bauen wollt. Denn ihr habt das Problem nicht, das euer Bot hat. Euch ist das zu abstrakt, aber wenn ihr das nicht begreift, wird er nie dort hinkommen, wo er hin soll. Ihr habt Augen, die euch ohne zu denken den Absolutwert geben, wie weit der Abstand des Cursors eurer Maus zum Startbutton jetzt ist. Die Maus hat einen Weggeber intern, doch ihr kontrolliert ständig, ob die Werte korrekt sind und korrigiert diese falls nötig! Das kann euer Roboter nicht. Das heisst, wenn eine Achse sich schwerer dreht als die andere, wird er ständig im Kreis fahren. Ohne dass ihr das in den Messwerten sehen könnt.&lt;br /&gt;
&lt;br /&gt;
==Weggeber==&lt;br /&gt;
Die [[Sensorarten#Drehgeber_Sharp_GP1A30|Weggeber]] existieren meistens in Form der Odometrie. Das heisst, die Drehung der Antriebsachse wird direkt erfasst. Das kann erfolgen mit einem Schrittmotor (wobei dies indirekt ist, da ihr hier die Werte vorgebt) oder mit einer Lochscheibe, die dann die Schritte mittels Lichtschranke zählt. Oder mit Tastern und einem Zahnrad. &lt;br /&gt;
Nicht zur Odometrie gehörend, aber auch Weggeber, sind „mitlaufende“ zählende Räder (z.B eine Kugelmaus) oder aber eine optische Maus. Oder ein Seil, das ihr von einem Lotpunkt mitzieht. &lt;br /&gt;
&lt;br /&gt;
Diese Weggeber sind ungenau und verfälschen immer das Ergebnis. Wenn ihr den Roboter über längere Strecken fahren lässt, braucht ihr den 2. Typ, um ihn neu einzukalibrieren. &lt;br /&gt;
&lt;br /&gt;
===Absolutwertgeber:===&lt;br /&gt;
Diese Methode sagt euch, wo auf einer Ebene ihr euch exakt befindet; in X- und Y-Achse aufgesplittet. &lt;br /&gt;
&lt;br /&gt;
Es gibt mehrere Methoden, die ich ohne besondere Reihenfolge aufliste: &lt;br /&gt;
&lt;br /&gt;
====Peilung====&lt;br /&gt;
Das [[Sensorarten#Sharp_GP2D12|IR-Abstandsmessungsprinzip]] funktioniert so, dass sich ein Turm auf dem Roboter befindet. Diese Sensoren scannen den Raum ab. Mittels weiterer Sensoren ([[Sensorarten#Kompa.C3.9F|Kompasssensoren]]) kann man berechnen, wo im Raum man sich befindet. Nur bedingt einsetzbar, da ja Objekte die Wand verdecken. &lt;br /&gt;
Das Bakensystem funktioniert nach dem Einpeilungsprinzip. Das heißt, in einem Raum kennen wir mindestens 2 Punkte (Baken), die dann mit dem Roboter ein Ebenendreieck aufspannen. Mittels Berechnungen kann dann die unbekannte Roboter-Position exakt bestimmt werden. Es gibt verschiedene Methoden, doch hier die Wichtigsten: &lt;br /&gt;
&lt;br /&gt;
* Aktive Bake: Die Baken senden ein Signal aus, das dann vom Roboter empfangen wird (z.B. IR). Das ist die einfachste Methode, wenn auch nicht die eleganteste. Denn dadurch muss sich die Technik über den Roboter hinaus in den Raum ausbreiten und das wiederum kollidiert mit dem Prinzip des autonomen Roboters. Die meisten Absolutwertgeber mit Baken gehen diesen Weg. &lt;br /&gt;
&lt;br /&gt;
* Passive Bake: Nur das Signal zu dem Roboter wird zurückgesendet, das dieser ausstrahlt. Das Problem ist, dass bei diesem System der Aufwand auf dem Roboter höher ist und dass der Batterieverbauch größer wird. Aber wir haben dann auch einen wirklich autonomen Roboter. &lt;br /&gt;
&lt;br /&gt;
-Aus dem Alltag- &lt;br /&gt;
Es gibt Veranstaltungen/Wettkämpfe, die nur eine Bake zulassen. Diese soll dabei nicht helfen, um herauszufinden, wo sich der Roboter im Raum befindet, sondern nur, wo er hin soll bzw. wo sein „Feind“ ist. &lt;br /&gt;
&lt;br /&gt;
====Das Bodenmarkierungsprinzip====&lt;br /&gt;
wird meistens eingesetzt, wenn der Roboter sich nur in einem bestimmten Feld oder auf einer bestimmten Bahn aufhalten soll. Dabei werden passive oder aktive Elemente im Boden eingelassen, die dann von Onboard-Sensoren wahrgenommen werden. Beispiel hierfür sind Rasenmäherbots oder autonome Fahrzeuge in Werkshallen. &lt;br /&gt;
&lt;br /&gt;
====[[GPS]]====&lt;br /&gt;
Neben dem Bakensystem existiert noch ein raumunabhängiges System; das [[GPS]]. Dieses ist aber sehr aufwändig. Denn es bezieht Zeitsignale von Satelliten, die dann verglichen werden und ist meist draußen besser zu empfangen. Auch ließ das US-Militär das Signal verschlechtern, so dass es nur sehr ungenau war. Heutzutage ohne Störsignal schafft man auch nur Genauigkeiten von einigen Metern. Wenn man genauere Werte braucht, benötigt man mindestens 2 Empfänger und muss diese miteinander vergleichen. Einer der Empfänger steht dann normalerweise an einem festen Punkt. Das nennt sich Differential-GPS (DGPS). Näheres unter dem Artikel [[GPS]].&lt;br /&gt;
&lt;br /&gt;
Weitere Methoden sind nicht zu gebrauchen oder sind nur Abarten der hier erwähnten Methoden.&lt;br /&gt;
&lt;br /&gt;
===Umweltsensoren===&lt;br /&gt;
Sie sind meist erst in der letzten Ausbaustufe beim Roboter interessant und sollen unserem Freund helfen, sich in der Umwelt zurechtzufinden. &lt;br /&gt;
&lt;br /&gt;
Dabei gibt es Interaktionsensoren, wie Drucksensoren oder Mikrofone. Mikrofone lassen den Roboter erkennen, ob Geräusche vorhanden sind. Richtig: ob, nicht wo. Dazu muss das Mikrofon entweder gerichtet sein und sich im Raum drehen können oder aber es müssen sich Mikrofone in vier Ecken starr auf dem Roboter befinden. &lt;br /&gt;
&lt;br /&gt;
Wenn der Roboter eine Solarzelle hat, dann braucht er Lichtsensoren, die ihn zur größten Lichtquelle bringen. &lt;br /&gt;
&lt;br /&gt;
====Rauchsensoren==== lassen den Roboter zwar erkennen, dass sich Rauch im Raum befindet. Doch was nützt es, wenn dieser Rauch erst in einer Höhe von 40 cm erkannt wird? Um z.B. Räume auf Giftgas zu testen braucht es einen Gasmesser. Beide Sensoren arbeiten unterschiedlich. Während Rauchmelder alle Partikel ohne Ausnahme erkennen, haben Gasmesser nur eine begrenzte Sammlung an zu erkennenden Gasen. &lt;br /&gt;
&lt;br /&gt;
====Temperatursensoren==== ermöglichen dem Bot die Temperatur zu messen, um z.B. aus der Sonne zu gehen oder um einzelne Bauelemente vor Überhitzung zu schützen.&lt;br /&gt;
&lt;br /&gt;
==Nachsatz==&lt;br /&gt;
Es gibt dutzende Sensoren und Sensoranlagen, die unserem Bot helfen sich in der Umwelt zurechtzufinden. Je mehr man hat, umso mehr kann man mit diesen spielen, um z.B. Gewohnheiten zu programmieren. Aber wenn man seinen Bot auf eine Aufgabe ausrichtet, sind es diese, die das i-Tüpfelchen bringen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Autor: honkitonk / Wiki Übernahme Picnick''&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Sensorarten]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Sensoren]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Sensoren&amp;diff=20630</id>
		<title>Sensoren</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Sensoren&amp;diff=20630"/>
				<updated>2012-08-22T13:42:47Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Direkte Sensoren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Sensoren==&lt;br /&gt;
Jeder, der sich einen Roboter baut, wird schnell zu dem Punkt kommen, wo er möchte, dass sein Roboter „sieht“. &lt;br /&gt;
Sensoren müssen hauptsächlich drei Aufgaben erledigen. Die ersten beiden sind Kollisionsschutz und Navigation. Diese unterscheiden sich in der Funktionsweise vor allem in der Interpretation, im Programm und im Aufbau am Roboter. Die dritte Art sind Sensoren, die ihn mit der Umwelt in Kontakt treten lassen. &lt;br /&gt;
&lt;br /&gt;
Grundsätzlich müssen alle Sensoren diese Merkmale aufweisen: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Passiv oder aktiv?=== &lt;br /&gt;
Manche Sensoren (z.B. IR) brauchen eine aktive Quelle (hier die IR-LED), die dann aber einen Mehrverbrauch an Strom bedeutet. Passive Sensoren, wie zB Taster, bekommen ihre Signale aus der Umwelt (hier Stoß). Zu ihnen zählen die meisten Umweltgrößen, wie Temperatur und Feuchtigkeit, Licht und Vibration oder Kraft (Stoß). &lt;br /&gt;
&lt;br /&gt;
===Einfachheit===&lt;br /&gt;
Ein Sensor muss einfach sein. Denn was nützt es uns, wenn wir den Sensor nicht kalibrieren können oder der Aufbau zu schwer ist? Doch Sensoren, die nicht in einem einzigen Gehäuse untergebracht sind, sind äußerst selten. Dann besteht nur noch der Wunsch, dass die meist zweidrahtigen Sensoren auch einfach anzuschließen sind. Deswegen ist es manchmal von Vorteil, sich vorgefertigte Anschlüsse zu kaufen, anstatt diese in mühsamer Kleinarbeit selber zu erstellen. &lt;br /&gt;
&lt;br /&gt;
===Auswertbarkeit in Echtzeit===&lt;br /&gt;
Alle Sensoren, die zunächst in Frage kommen, basieren auf dem Prinzip des Spannungsteilers. Das heißt, es wird eine Urspannung eingegeben und eine Teilspannung kommt heraus. Diese Differenz können wir erfassen und mittels Wertetabelle im Programm auswerten. Aber durch Störeinflüsse in der Umwelt kann es vorkommen, dass die berechneten Werte abweichen. Jeder Messtechniker weiß, dass allein die Messung an sich schon das Messergebnis verfälscht.&lt;br /&gt;
&lt;br /&gt;
===Robustheit===&lt;br /&gt;
Wir werden am Anfang sicher nicht unseren Roboter in einer Morastlandschaft einsetzen, aber auch schon ein Stoß gegen die Wand hat manchen Roboter ausgeknockt. Schon normaler Hausstaub kann und wird Linsen trüben und Messwerte verschlechtern. Das heisst: Wenn ein Sensor gekauft wird, muss er der Situation angemessen sein.&lt;br /&gt;
&lt;br /&gt;
==Aufgaben für Roboter==&lt;br /&gt;
Natürlich muss man sich, bevor der Roboter steht, schon im Klaren sein, was seine Aufgaben sind. Auch wenn diese so weitgefasst sind wie „Karte erstellen – Raumüberwachung – dabei einer Linie folgen“. Jeder Sensor braucht Platz und verringert die Einsatzdauer. Nicht jeder Sensor ist für jede Arbeit gedacht und zum Schluss spielt das Geld eine Rolle, denn mancher Sensor kostet schon 30 Euro. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sensoren für den Kollisionsschutz===&lt;br /&gt;
Die wichtigsten Sensoren auf einem Roboter sind die Kollisionssensoren. Diese schützen den Roboter vor Zusammenstößen und Abstürzen in einen Schacht. Dabei kann man diese Gruppe in direkte und indirekte Sensoren unterteilen. &lt;br /&gt;
&lt;br /&gt;
====Direkte Sensoren====&lt;br /&gt;
Sie sollen den Zusammenstoß nicht verhindern, sondern dabei das Signal ausgeben. In letzter Zeit werden diese Sensoren noch gepolstert, damit beim Zusammenstoß keine zu großen Kräfte auftreten. &lt;br /&gt;
Am Einfachsten geht dies mit einem Taster, der am Chassis befestigt ist. Da dies sehr kurze Reaktionszeiten mit sich bringt, haben einige Roboter Fühler, um diese Zeit zu verlängern. Eine weitere Methode ist es, eine Stoßstange zu entwickeln, die dann an den Tastern (direkt oder indirekt) befestigt wird. Dabei kann diese Stoßstange auch gepolstert sein. Eine nun neuere Methode ist es, Luftschläuche zu verwenden. Die dämpfen den Stoß ab und sind dabei an einem Drucksensor angeschlossen, der das Zusammenquetschen erkennt und ein Signal ausgibt.&lt;br /&gt;
&lt;br /&gt;
Als Taster kann auch ein virtueller Bumper verwendet werden. Das Prinzip ist, eine Stromerhöhung eines Antriebsmotors beim Kollidieren mit einem Hindernis als Bumper zu emulieren. Das ermöglicht praktisch einen Roboter so zu steuern, wie wenn auf seinem ganzen Umfang echte Bumpers befestigt wären. Beim Kollidieren mit einem Hindernis wird der Ausgang der Schaltung (siehe Skizze) mit dem GND kurzgeschlossen, genauso wie wenn ein echter Bumper betätigt wäre. Hardware- bzw softwaremäßig kann man den Wirkungsbereich des virtuellen Bumpers nach individuellen Wünschen gestalten (siehe eventuell dazu: http://www.roboternetz.de/community/threads/55075-Selbstsau .&lt;br /&gt;
&lt;br /&gt;
Der Spannungsabfall auf dem Shunt (Rs) sollte bei normalem Fahren sicher unter der Spannung liegen, die der Transistor (T) zum Leiten braucht (ca. 0,7 V für normale und ca. 1,4 V für Darlington-Transistoren), z.B. 0,4 V. Bei Kollision mit einem Hindernis sollte der Spannungsabfall auf dem Rs sicher die o.g. Spannung überschreiten und z.B. 0,8 V oder höher sein. Der Elko (C) verzögert den Anstieg der Spannung auf dem Rs für den Anlaufstrom des Motors, der bis ca. 5-fach größer als beim unbehinderten Fahren ist. Für einen konkreten Motor und µC müssen die Rs, Rp (eventuell innerer pull-up) und C entsprechend angepasst werden, damit die Schaltung zufriedenstellend funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Beispielschaltung wurde fur einen DC-Getriebemotor mit folgenden Parametern entwickelt:&lt;br /&gt;
&lt;br /&gt;
- Strom beim unbehindertem Fahren: ca. 0,4 A&lt;br /&gt;
&lt;br /&gt;
- Strom beim gebremstem Motor: ca. 0,8 A&lt;br /&gt;
&lt;br /&gt;
- Anlaufstrom beim Anfahren: ca. 2 A&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                                VCC&lt;br /&gt;
                                                 +&lt;br /&gt;
                                                 |&lt;br /&gt;
                                                .-.&lt;br /&gt;
                                                | | Rp&lt;br /&gt;
                     +-----------------------+  | | 1k&lt;br /&gt;
                     |                       |  '-'&lt;br /&gt;
                     |         Rb            |   |&lt;br /&gt;
                     |                    +------+-&amp;gt; zum µC Pin&lt;br /&gt;
                     |         1k         |  |       (anstatt Bumper)&lt;br /&gt;
                     |        ___       |/   |&lt;br /&gt;
     von H-Brücke &amp;gt;--------+-|___|-+----| T  |&lt;br /&gt;
    (üblich mit GND  |     |       |    |&amp;gt;   |&lt;br /&gt;
     verbunden)      |    .-.      |+     |  |&lt;br /&gt;
                     | Rs | |     === C  === |&lt;br /&gt;
                     |    | |     /-\    GND |&lt;br /&gt;
                     |  1 '-'      | 100µ    |&lt;br /&gt;
                     |     |       |         |&lt;br /&gt;
                     |    ===     ===        |&lt;br /&gt;
                     |    GND     GND        |&lt;br /&gt;
                     |                       |&lt;br /&gt;
                     +-----------------------+&lt;br /&gt;
                         virtueller Bumper&lt;br /&gt;
&lt;br /&gt;
Als virtueller Bumper kann auch an ein Antriebsrad angebrachter Impulsgeber softwaremässig emuliert werden.&lt;br /&gt;
&lt;br /&gt;
====Indirekte Sensoren====&lt;br /&gt;
Sie sollen helfen, den Zusammenstoß zu vermeiden, um bestenfalls noch Zeit zu geben, einen optimalen Weg ums Hindernis herum zu finden. Diese haben ein größeres Problem, da sie meist keine 360-Grad-„Rundumsicht“ garantieren können. Das bedeutet, dass die meisten Roboter diesen Typ der Sensoren in Fahrtrichtung eingebaut haben, um diese Aufgabe zu erfüllen. Was auch effizient ist, denn solche Sensoren sind sehr teuer und müssen ständig vom Programm überwacht werden. &lt;br /&gt;
&lt;br /&gt;
Diese Sensoren werden bei neueren Autos auch als Parkhilfe angeboten.&lt;br /&gt;
&lt;br /&gt;
==Probleme==&lt;br /&gt;
Das Problem der Sensoren ist ihre räumliche Begrenztheit. Denn schon 5 Meter sind sehr lang. Aber auf der anderen Seite wollen die meisten ohnehin keine 5 Meter „vorausschauen“. &lt;br /&gt;
[[Sensorarten|Es gibt mehrere Typen]]. Am bekanntesten sind die [[Sensorarten#optische_Sensoren|IR-Sensoren]]. Diese sind gut für lange Distanzen, aber haben das Problem, dass sie gebündelt sind und somit Zwischenräume schwer abdecken können. Besser sind dort [[Sensorarten#Ultraschall_Sensoren|Ultraschallsensoren]], die aber teurer sind. Etwas in der Nische ist das Radar-System; es ist ein sehr aufwendiges und teueres System und die Auswertung der Daten ist komplex. Es bietet aber den besten Schutz gegen Zusammenstöße, da dieses System nicht auf einen Punkt gerichtet ist, sondern die ganze Fläche abscannt. &lt;br /&gt;
&lt;br /&gt;
Problem beider Systeme: &lt;br /&gt;
Das ist die Höhe. Leider ist unser Roboter dreidimensional und bewegt sich zweidimensional. Das heißt, es spannen sich mehrere Ebenen auf, die überwacht werden wollen. Denn wenn dies nicht geschieht, stößt der Roboter gegen eine Tischplatte, weil er diese nicht erkannt hat oder gegen ein Hindernis, das unter den Sensoren hindurch rutschte. &lt;br /&gt;
Deswegen bemüht man sich, den Roboter so flach wie möglich zu halten und das Fahrgestell so zu bauen, dass man flache Hindernisse überfahren kann. Es hilft also, sich darüber vorher Gedanken zu machen. &lt;br /&gt;
Je nachdem wo der Roboter zum Einsatz kommt tun sich manchmal Abgründe auf (z.B. Tischplatte). Diese müssen erkannt werden. Deswegen ist es erforderlich, Abstandssensoren noch unten zu richten, um einen Absturz zu vermeiden. Dabei sollte man indirekte Sensoren einsetzen, denn was nützt es, wenn der Taster erkannt hat, dass nun ein Loch da ist, aber der Roboter bis zur Reaktion schon auf dem Boden aufschlägt?&lt;br /&gt;
&lt;br /&gt;
==Navigation==&lt;br /&gt;
Nun gibt es hier viele Arten, wie die Navigation erfolgen kann. Ich tue 2 Felder auf. Wenn unser Freund neue Welten erkunden soll oder in einem Spiel gegen eine Mannschaft antritt, dann braucht er andere Sensoren, als wenn er routiniert Wege abfahren soll. Obwohl sich die Felder überschneiden. &lt;br /&gt;
&lt;br /&gt;
Alle Navigationssysteme bauen auf 2 Quellen der Navigation auf: [[Sensorarten#Drehgeber_Sharp_GP1A30|inkrementale Weggeber]] und Absolutwertgeber. &lt;br /&gt;
&lt;br /&gt;
Dies ist das größte Problem, wenn ihr einen Bot bauen wollt. Denn ihr habt das Problem nicht, das euer Bot hat. Euch ist das zu abstrakt, aber wenn ihr das nicht begreift, wird er nie dort hinkommen, wo er hin soll. Ihr habt Augen, die euch ohne zu denken den Absolutwert geben, wie weit der Abstand des Cursors eurer Maus zum Startbutton jetzt ist. Die Maus hat einen Weggeber intern, doch ihr kontrolliert ständig, ob die Werte korrekt sind und korrigiert diese falls nötig! Das kann euer Roboter nicht. Das heisst, wenn eine Achse sich schwerer dreht als die andere, wird er ständig im Kreis fahren. Ohne dass ihr das in den Messwerten sehen könnt.&lt;br /&gt;
&lt;br /&gt;
==Weggeber==&lt;br /&gt;
Die [[Sensorarten#Drehgeber_Sharp_GP1A30|Weggeber]] existieren meistens in Form der Odometrie. Das heisst, die Drehung der Antriebsachse wird direkt erfasst. Das kann erfolgen mit einem Schrittmotor (wobei dies indirekt ist, da ihr hier die Werte vorgebt) oder mit einer Lochscheibe, die dann die Schritte mittels Lichtschranke zählt. Oder mit Tastern und einem Zahnrad. &lt;br /&gt;
Nicht zur Odometrie gehörend, aber auch Weggeber, sind „mitlaufende“ zählende Räder (z.B eine Kugelmaus) oder aber eine optische Maus. Oder ein Seil, das ihr von einem Lotpunkt mitzieht. &lt;br /&gt;
&lt;br /&gt;
Diese Weggeber sind ungenau und verfälschen immer das Ergebnis. Wenn ihr den Roboter über längere Strecken fahren lässt, braucht ihr den 2. Typ, um ihn neu einzukalibrieren. &lt;br /&gt;
&lt;br /&gt;
===Absolutwertgeber:===&lt;br /&gt;
Diese Methode sagt euch, wo auf einer Ebene ihr euch exakt befindet; in X- und Y-Achse aufgesplittet. &lt;br /&gt;
&lt;br /&gt;
Es gibt mehrere Methoden, die ich ohne besondere Reihenfolge aufliste: &lt;br /&gt;
&lt;br /&gt;
====Peilung====&lt;br /&gt;
Das [[Sensorarten#Sharp_GP2D12|IR-Abstandsmessungsprinzip]] funktioniert so, dass sich ein Turm auf dem Roboter befindet. Diese Sensoren scannen den Raum ab. Mittels weiterer Sensoren ([[Sensorarten#Kompa.C3.9F|Kompasssensoren]]) kann man berechnen, wo im Raum man sich befindet. Nur bedingt einsetzbar, da ja Objekte die Wand verdecken. &lt;br /&gt;
Das Bakensystem funktioniert nach dem Einpeilungsprinzip. Das heißt, in einem Raum kennen wir mindestens 2 Punkte (Baken), die dann mit dem Roboter ein Ebenendreieck aufspannen. Mittels Berechnungen kann dann die unbekannte Roboter-Position exakt bestimmt werden. Es gibt verschiedene Methoden, doch hier die Wichtigsten: &lt;br /&gt;
&lt;br /&gt;
* Aktive Bake: Die Baken senden ein Signal aus, das dann vom Roboter empfangen wird (z.B. IR). Das ist die einfachste Methode, wenn auch nicht die eleganteste. Denn dadurch muss sich die Technik über den Roboter hinaus in den Raum ausbreiten und das wiederum kollidiert mit dem Prinzip des autonomen Roboters. Die meisten Absolutwertgeber mit Baken gehen diesen Weg. &lt;br /&gt;
&lt;br /&gt;
* Passive Bake: Nur das Signal zu dem Roboter wird zurückgesendet, das dieser ausstrahlt. Das Problem ist, dass bei diesem System der Aufwand auf dem Roboter höher ist und dass der Batterieverbauch größer wird. Aber wir haben dann auch einen wirklich autonomen Roboter. &lt;br /&gt;
&lt;br /&gt;
-Aus dem Alltag- &lt;br /&gt;
Es gibt Veranstaltungen/Wettkämpfe, die nur eine Bake zulassen. Diese soll dabei nicht helfen, um herauszufinden, wo sich der Roboter im Raum befindet, sondern nur, wo er hin soll bzw. wo sein „Feind“ ist. &lt;br /&gt;
&lt;br /&gt;
====Das Bodenmarkierungsprinzip====&lt;br /&gt;
wird meistens eingesetzt, wenn der Roboter sich nur in einem bestimmten Feld oder auf einer bestimmten Bahn aufhalten soll. Dabei werden passive oder aktive Elemente im Boden eingelassen, die dann von Onboard-Sensoren wahrgenommen werden. Beispiel hierfür sind Rasenmäherbots oder autonome Fahrzeuge in Werkshallen. &lt;br /&gt;
&lt;br /&gt;
====[[GPS]]====&lt;br /&gt;
Neben dem Bakensystem existiert noch ein raumunabhängiges System; das [[GPS]]. Dieses ist aber sehr aufwändig. Denn es bezieht Zeitsignale von Satelliten, die dann verglichen werden und ist meist draußen besser zu empfangen. Auch ließ das US-Militär das Signal verschlechtern, so dass es nur sehr ungenau war. Heutzutage ohne Störsignal schafft man auch nur Genauigkeiten von einigen Metern. Wenn man genauere Werte braucht, benötigt man mindestens 2 Empfänger und muss diese miteinander vergleichen. Einer der Empfänger steht dann normalerweise an einem festen Punkt. Das nennt sich Differential-GPS (DGPS). Näheres unter dem Artikel [[GPS]].&lt;br /&gt;
&lt;br /&gt;
Weitere Methoden sind nicht zu gebrauchen oder sind nur Abarten der hier erwähnten Methoden.&lt;br /&gt;
&lt;br /&gt;
===Umweltsensoren===&lt;br /&gt;
Sie sind meist erst in der letzten Ausbaustufe beim Roboter interessant und sollen unserem Freund helfen, sich in der Umwelt zurechtzufinden. &lt;br /&gt;
&lt;br /&gt;
Dabei gibt es Interaktionsensoren, wie Drucksensoren oder Mikrofone. Mikrofone lassen den Roboter erkennen, ob Geräusche vorhanden sind. Richtig: ob, nicht wo. Dazu muss das Mikrofon entweder gerichtet sein und sich im Raum drehen können oder aber es müssen sich Mikrofone in vier Ecken starr auf dem Roboter befinden. &lt;br /&gt;
&lt;br /&gt;
Wenn der Roboter eine Solarzelle hat, dann braucht er Lichtsensoren, die ihn zur größten Lichtquelle bringen. &lt;br /&gt;
&lt;br /&gt;
====Rauchsensoren==== lassen den Roboter zwar erkennen, dass sich Rauch im Raum befindet. Doch was nützt es, wenn dieser Rauch erst in einer Höhe von 40 cm erkannt wird? Um z.B. Räume auf Giftgas zu testen braucht es einen Gasmesser. Beide Sensoren arbeiten unterschiedlich. Während Rauchmelder alle Partikel ohne Ausnahme erkennen, haben Gasmesser nur eine begrenzte Sammlung an zu erkennenden Gasen. &lt;br /&gt;
&lt;br /&gt;
====Temperatursensoren==== ermöglichen dem Bot die Temperatur zu messen, um z.B. aus der Sonne zu gehen oder um einzelne Bauelemente vor Überhitzung zu schützen.&lt;br /&gt;
&lt;br /&gt;
==Nachsatz==&lt;br /&gt;
Es gibt dutzende Sensoren und Sensoranlagen, die unserem Bot helfen sich in der Umwelt zurechtzufinden. Je mehr man hat, umso mehr kann man mit diesen spielen, um z.B. Gewohnheiten zu programmieren. Aber wenn man seinen Bot auf eine Aufgabe ausrichtet, sind es diese, die das i-Tüpfelchen bringen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Autor: honkitonk / Wiki Übernahme Picnick''&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Sensorarten]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Sensoren]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20483</id>
		<title>Datenblätter lesen und verstehen</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20483"/>
				<updated>2012-08-04T03:18:17Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Typical Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Über diesen Artikel==&lt;br /&gt;
!!!Dieser Artikel ist noch in Arbeit!!!&lt;br /&gt;
&lt;br /&gt;
In der Elektronik und/oder Robotik kommt man ohne Datenblätter (engl. datasheet) nicht wirklich weit. Nicht jeder Hobby-Bastler hatte eine Ausbildung im Elektrobereich&lt;br /&gt;
oder kann sich auf  Anhieb mit den Datenblättern anfreunden. Deswegen sollte dieser Artikel als kleine Hilfe zum Einstieg in die umfangreiche Bibliothek der Datenblätter dienen. Es muss auch erwähnt werden, dass in diesem Artikel kein Datenblatt bis ins kleinste Detail erklärt wird.&lt;br /&gt;
&lt;br /&gt;
==Nutzen von Datenblättern==&lt;br /&gt;
Datenblätter sind nicht nur bei Neuentwicklungen, sondern auch bei bestehender Hardware sehr nützlich. Anhand dieser nützlichen, meistens im PDF-Format verfügbaren Dokumenten, kann man für seine Projekt passende Bauteile verwenden ohne einen Fehlkauf zu tätigen oder das Bauteil zu zerstören. Aber auch bei der Fehlersuche  sind die Datenblätter sehr nützlich. Anhand der Information, die darin steht, kann man Eingangs- und Ausgangssignale bestimmen, das gemessene Signal mit dem erwarteten Signal vergleichen, ob das Bauteil den richtigen Strom verbraucht oder doch etwas mehr, was auf einen Kurzschluss deuten könnte.&lt;br /&gt;
&lt;br /&gt;
==Quellen==&lt;br /&gt;
Es gibt eine ziemlich überschaubare Anzahl von Quellen, woher man seine Datenblätter beziehen kann.&lt;br /&gt;
*Direkt im Online-Shop, wo man seine Elektronikteile gekauft hat oder kaufen kann. (Download in Artikel-Beschreibung)&lt;br /&gt;
*Diverse Datenbänke (z.B. [http://www.datasheetcatalog.com.de www.datasheetcatalog.com])&lt;br /&gt;
*Datenkataloge in Papierform (etwas veraltete Methode)&lt;br /&gt;
*Von der Website des Herstellers &lt;br /&gt;
&lt;br /&gt;
Gängige ICs wie der Spannungsregler 7805 werden teils von mehrere Herstellern gefertigt, so dass man ggf. auch mehrere Datenblätter (mit teils deutlich unterschiedlichem Umfang) zur Auswahl hat.  Meistens ist die Menge von Informationen und Beispielschaltungen proportional zur Dateigröße des Datenblatts.&lt;br /&gt;
&lt;br /&gt;
==Angaben in Datenblättern==&lt;br /&gt;
Um die Angaben in Datenblättern anhand von Beispielen zu erklären, wurden folgende Beispiel-Bauteile ausgewählt.&lt;br /&gt;
*7805 Spannungsregler&lt;br /&gt;
*LED&lt;br /&gt;
*LDR&lt;br /&gt;
*ULN2804 Treiber&lt;br /&gt;
===Erste Seite===&lt;br /&gt;
In den meisten Fällen ist ein kurzer Blick auf die erste Seite schon ausreichend um die wesentlich Kenndaten im Groben zu erfahren. Aber auch hier kriegen manche schon Panik. Grund dafür ist oft die Marketing-Sprache. Das sollte aber einen nicht abschrecken. Es nimmt einem niemand übel, wenn man noch ein Fenster mit leo.org offen hat.&lt;br /&gt;
&lt;br /&gt;
Die groben Daten ganz am Anfang sind aber auch mit Vorsicht zu sehen: das sind teils Werbeaussagen, die nur unter bestimmten günstigen Bedingungen (z.B. niedrige Temperatur) gültig sind.&lt;br /&gt;
&lt;br /&gt;
Schauen wir doch mal in das Datenblatt von dem Festspannungsregler 7805 ([http://www.datasheetcatalog.org/datasheets/228/390068_DS.pdf Link zum Datenblatt])&lt;br /&gt;
Angaben auf der ersten Seite&lt;br /&gt;
&lt;br /&gt;
===Absolute Maximum Ratings===&lt;br /&gt;
Diesen Abschnitt findet man in fast jedem Datenblatt zu elektronischen Bauteilen. Hier wird aufgeführt was das Bauteil vertragen kann, also so etwas wie garantierte Maximalwerte für Spannung, Strom, Temperatur oder Verlustleistung. Bei den Grenzwerten ist nur garantiert, dass das Bauteil nicht kurzfristig kaputt geht - es ist nicht garantiert das bei den Bedingungen die normale Funktion noch gegeben ist. Auch kann eine dauerhafte Belastung bis zum Grenzwert zu einer relativ kurzen Lebensdauer führen.&lt;br /&gt;
&lt;br /&gt;
Die Parameter Absolute Maximum Ratings sind am wichtigsten für alle Bauteile und müssen so angehalten werden, dass keiner davon überschritten wird, weil das meistens zur Zerstörung des Bauteils führt. Zur sicherer Zerstörung jedes Bauteils führt Wärmeentwicklung im Gehause und überschritten der inneren Temperatur des Halbleiters ca. 150 °C. Je besser die Wärme in die Umgebung durch Kühlkörper abgeführt wird um so mehr Wärme darf entstehen. Das heisst, das die Nutzliche Verlustleistung bei 25 °C des Gehäuses und nicht der Umgebung bedeutet. Beispielweise für den Transistor BU508 ist die Verlustleistung 125 W bei Gehäusetemperatur 25 °C und 0 W bei 150 °C. Praktisch kann man ohne Lüfterkühlung und riesiegen Kühlkörper ca. 1/3 der max. Verlustleitung nutzen.&lt;br /&gt;
&lt;br /&gt;
Für das Beispiel 7805 finden sich im Datenblatt eher wenige Daten zur Temperatur und der maximalen Spannung, denn das IC besitzt einen internen Schutz gegen so etwas wie eine zu hohe Verlustleistung oder zu viel Strom am Ausgang. Die Angaben zum Wärmewiderstand, die die im verlinkten Datenblatt zu finden sind, gehören streng genommen wo anders hin.&lt;br /&gt;
&lt;br /&gt;
===Electrical Characteristics===&lt;br /&gt;
In diesem Abschnitt werden die wichtigsten Kenndaten angegeben. Hier wird also erklärt wie sich das IC verhalten sollte und mit welchen Abweichungen vom Idealfall man rechnen muss. Ganz am Anfang stehen üblicherweise die Randbedingungen wie Temperatur, Versorgungsspannung und ggf. die Schaltung für die die Daten gelten. Diese Werte kann man oft als Empfehlung für die Versorgungsspannung oder ähnliches sehen. Für die einzelnen Parameter werden dann meist minimale, maximale und typischen Werte angegeben. &lt;br /&gt;
&lt;br /&gt;
Eine Schwierigkeit für den Anfänger es ist dabei die Bedeutung der Parameter zu verstehen, bzw. in der oft langen Tabelle den richtigen zu finden. Einige spezielle Parameter werden ggf. im Datenblatt definiert, die meisten der aber einfach nur mit englischem Namen und Symbol angegeben. Als Hilfe kann hier z.B. die englische Version von Wikipedia dienen - oft sind da die englischen Parameter erklärt.  &lt;br /&gt;
&lt;br /&gt;
Statt als Zahlenwert in der Tabelle werden einige Eigenschaften dann im folgenden Abschnitt als Kurve bzw. Kennlinie angegeben. Wenn auch weniger genau als die Zahlenwerte, enthalten die Kurven oft deutlich mehr Informationen über das Verhalten der ICs.&lt;br /&gt;
&lt;br /&gt;
==== Parameter ====&lt;br /&gt;
Hier eine kurze Liste der häufiger vorkommenden Parameter, mit einer kurzen Erklärung:&lt;br /&gt;
*&amp;quot;Junction Temperature&amp;quot; : Dies ist die Temperatur des aktiven Teils im Halbleiter. Sie ist um das Produkt aus Verlustleistung und Wärmewiderstand (thermal resistance) höher als die des Gehäuses.  &lt;br /&gt;
*&amp;quot;Quiescent Current&amp;quot; , Iq : Dies ist der Ruhestrom, also der Stromverbrauch des ICs. &lt;br /&gt;
*... &amp;quot;Voltage Drift&amp;quot;,  : Gibt an wie sehr sich eine Spannung bei Änderung der Temperatur ändert.&lt;br /&gt;
&lt;br /&gt;
* ... &amp;quot;Temperature coefficient&amp;quot; bezeichnet ebenfalls die Temperaturabhängigkeit, allerdings hier relativ zum Normalwert.&lt;br /&gt;
* ... &amp;quot;Leakage Current&amp;quot; : Dies ist ein Leckstrom, also ein Strom wo das Bauteil im Idealfall sperren soll. Besonders bei höherer Temperatur sperren Halbleiter aber nicht perfekt, und es fließt trotzdem ein kleiner Strom. Meist wird nur eine obere Grenze angegeben, und der tatsächlicher Wert ist meist deutlich kleiner.&lt;br /&gt;
&lt;br /&gt;
===Typical Applications===&lt;br /&gt;
Unter diesem Punkt werden schließlich typische Schaltungen mit dem Bauteil aufgeführt. In der Regel findet man dabei die Grundschaltung auf die sich die Daten weiter oben beziehen. Teils sind hier aber auch andere teils reicht interessante Schaltungen zu finden, die zeigen was man noch alles mit dem Bauteil machen kann. In der Regel sind die Schaltungen ganz brauchbar. Das heißt aber nicht, dass die gezeigte Schaltungen optimal sind - nicht selten gibt es andere passendere oder günstigere Bauteile. &lt;br /&gt;
&lt;br /&gt;
Neben der reinen Schaltung finden sich teils auch noch Informationen zur Auslegung der Schaltung, also wie man die anderen Bauteile wie Kondensatoren oder Widerstände auslegen sollte. Bei der verlinkten Version für den 7805 ist hier allerdings fast nichts zu finden. Der 7805 ist eben relativ unkritisch - außer der hier in den Beispielen fehlenden Diode zwischen Ausgang und Eingang, die verhindert dass die Spannung am Ausgang deutlich größer wird als am Eingang.  &lt;br /&gt;
&lt;br /&gt;
Zu einigen Bauteilen bieten die Webseiten der Hersteller noch zusätzliche Informationen als sogenannte &amp;quot;Application Notes&amp;quot; an. Hier finden sich teils ausführlich beschriebene Schaltungen und nützliche Tipps zu den Bauteilen. Gerade hinsichtlich dieser zusätzlichen Informationen lohnt es sich bei mehr als einem Hersteller zu suchen.&lt;br /&gt;
&lt;br /&gt;
{{Ausbauwunsch| Erklärung von Kennlinien, App-Note's... Alles möglichst anfängertauglich erklären}}&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20482</id>
		<title>Datenblätter lesen und verstehen</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20482"/>
				<updated>2012-08-04T03:14:33Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Quellen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Über diesen Artikel==&lt;br /&gt;
!!!Dieser Artikel ist noch in Arbeit!!!&lt;br /&gt;
&lt;br /&gt;
In der Elektronik und/oder Robotik kommt man ohne Datenblätter (engl. datasheet) nicht wirklich weit. Nicht jeder Hobby-Bastler hatte eine Ausbildung im Elektrobereich&lt;br /&gt;
oder kann sich auf  Anhieb mit den Datenblättern anfreunden. Deswegen sollte dieser Artikel als kleine Hilfe zum Einstieg in die umfangreiche Bibliothek der Datenblätter dienen. Es muss auch erwähnt werden, dass in diesem Artikel kein Datenblatt bis ins kleinste Detail erklärt wird.&lt;br /&gt;
&lt;br /&gt;
==Nutzen von Datenblättern==&lt;br /&gt;
Datenblätter sind nicht nur bei Neuentwicklungen, sondern auch bei bestehender Hardware sehr nützlich. Anhand dieser nützlichen, meistens im PDF-Format verfügbaren Dokumenten, kann man für seine Projekt passende Bauteile verwenden ohne einen Fehlkauf zu tätigen oder das Bauteil zu zerstören. Aber auch bei der Fehlersuche  sind die Datenblätter sehr nützlich. Anhand der Information, die darin steht, kann man Eingangs- und Ausgangssignale bestimmen, das gemessene Signal mit dem erwarteten Signal vergleichen, ob das Bauteil den richtigen Strom verbraucht oder doch etwas mehr, was auf einen Kurzschluss deuten könnte.&lt;br /&gt;
&lt;br /&gt;
==Quellen==&lt;br /&gt;
Es gibt eine ziemlich überschaubare Anzahl von Quellen, woher man seine Datenblätter beziehen kann.&lt;br /&gt;
*Direkt im Online-Shop, wo man seine Elektronikteile gekauft hat oder kaufen kann. (Download in Artikel-Beschreibung)&lt;br /&gt;
*Diverse Datenbänke (z.B. [http://www.datasheetcatalog.com.de www.datasheetcatalog.com])&lt;br /&gt;
*Datenkataloge in Papierform (etwas veraltete Methode)&lt;br /&gt;
*Von der Website des Herstellers &lt;br /&gt;
&lt;br /&gt;
Gängige ICs wie der Spannungsregler 7805 werden teils von mehrere Herstellern gefertigt, so dass man ggf. auch mehrere Datenblätter (mit teils deutlich unterschiedlichem Umfang) zur Auswahl hat.  Meistens ist die Menge von Informationen und Beispielschaltungen proportional zur Dateigröße des Datenblatts.&lt;br /&gt;
&lt;br /&gt;
==Angaben in Datenblättern==&lt;br /&gt;
Um die Angaben in Datenblättern anhand von Beispielen zu erklären, wurden folgende Beispiel-Bauteile ausgewählt.&lt;br /&gt;
*7805 Spannungsregler&lt;br /&gt;
*LED&lt;br /&gt;
*LDR&lt;br /&gt;
*ULN2804 Treiber&lt;br /&gt;
===Erste Seite===&lt;br /&gt;
In den meisten Fällen ist ein kurzer Blick auf die erste Seite schon ausreichend um die wesentlich Kenndaten im Groben zu erfahren. Aber auch hier kriegen manche schon Panik. Grund dafür ist oft die Marketing-Sprache. Das sollte aber einen nicht abschrecken. Es nimmt einem niemand übel, wenn man noch ein Fenster mit leo.org offen hat.&lt;br /&gt;
&lt;br /&gt;
Die groben Daten ganz am Anfang sind aber auch mit Vorsicht zu sehen: das sind teils Werbeaussagen, die nur unter bestimmten günstigen Bedingungen (z.B. niedrige Temperatur) gültig sind.&lt;br /&gt;
&lt;br /&gt;
Schauen wir doch mal in das Datenblatt von dem Festspannungsregler 7805 ([http://www.datasheetcatalog.org/datasheets/228/390068_DS.pdf Link zum Datenblatt])&lt;br /&gt;
Angaben auf der ersten Seite&lt;br /&gt;
&lt;br /&gt;
===Absolute Maximum Ratings===&lt;br /&gt;
Diesen Abschnitt findet man in fast jedem Datenblatt zu elektronischen Bauteilen. Hier wird aufgeführt was das Bauteil vertragen kann, also so etwas wie garantierte Maximalwerte für Spannung, Strom, Temperatur oder Verlustleistung. Bei den Grenzwerten ist nur garantiert, dass das Bauteil nicht kurzfristig kaputt geht - es ist nicht garantiert das bei den Bedingungen die normale Funktion noch gegeben ist. Auch kann eine dauerhafte Belastung bis zum Grenzwert zu einer relativ kurzen Lebensdauer führen.&lt;br /&gt;
&lt;br /&gt;
Die Parameter Absolute Maximum Ratings sind am wichtigsten für alle Bauteile und müssen so angehalten werden, dass keiner davon überschritten wird, weil das meistens zur Zerstörung des Bauteils führt. Zur sicherer Zerstörung jedes Bauteils führt Wärmeentwicklung im Gehause und überschritten der inneren Temperatur des Halbleiters ca. 150 °C. Je besser die Wärme in die Umgebung durch Kühlkörper abgeführt wird um so mehr Wärme darf entstehen. Das heisst, das die Nutzliche Verlustleistung bei 25 °C des Gehäuses und nicht der Umgebung bedeutet. Beispielweise für den Transistor BU508 ist die Verlustleistung 125 W bei Gehäusetemperatur 25 °C und 0 W bei 150 °C. Praktisch kann man ohne Lüfterkühlung und riesiegen Kühlkörper ca. 1/3 der max. Verlustleitung nutzen.&lt;br /&gt;
&lt;br /&gt;
Für das Beispiel 7805 finden sich im Datenblatt eher wenige Daten zur Temperatur und der maximalen Spannung, denn das IC besitzt einen internen Schutz gegen so etwas wie eine zu hohe Verlustleistung oder zu viel Strom am Ausgang. Die Angaben zum Wärmewiderstand, die die im verlinkten Datenblatt zu finden sind, gehören streng genommen wo anders hin.&lt;br /&gt;
&lt;br /&gt;
===Electrical Characteristics===&lt;br /&gt;
In diesem Abschnitt werden die wichtigsten Kenndaten angegeben. Hier wird also erklärt wie sich das IC verhalten sollte und mit welchen Abweichungen vom Idealfall man rechnen muss. Ganz am Anfang stehen üblicherweise die Randbedingungen wie Temperatur, Versorgungsspannung und ggf. die Schaltung für die die Daten gelten. Diese Werte kann man oft als Empfehlung für die Versorgungsspannung oder ähnliches sehen. Für die einzelnen Parameter werden dann meist minimale, maximale und typischen Werte angegeben. &lt;br /&gt;
&lt;br /&gt;
Eine Schwierigkeit für den Anfänger es ist dabei die Bedeutung der Parameter zu verstehen, bzw. in der oft langen Tabelle den richtigen zu finden. Einige spezielle Parameter werden ggf. im Datenblatt definiert, die meisten der aber einfach nur mit englischem Namen und Symbol angegeben. Als Hilfe kann hier z.B. die englische Version von Wikipedia dienen - oft sind da die englischen Parameter erklärt.  &lt;br /&gt;
&lt;br /&gt;
Statt als Zahlenwert in der Tabelle werden einige Eigenschaften dann im folgenden Abschnitt als Kurve bzw. Kennlinie angegeben. Wenn auch weniger genau als die Zahlenwerte, enthalten die Kurven oft deutlich mehr Informationen über das Verhalten der ICs.&lt;br /&gt;
&lt;br /&gt;
==== Parameter ====&lt;br /&gt;
Hier eine kurze Liste der häufiger vorkommenden Parameter, mit einer kurzen Erklärung:&lt;br /&gt;
*&amp;quot;Junction Temperature&amp;quot; : Dies ist die Temperatur des aktiven Teils im Halbleiter. Sie ist um das Produkt aus Verlustleistung und Wärmewiderstand (thermal resistance) höher als die des Gehäuses.  &lt;br /&gt;
*&amp;quot;Quiescent Current&amp;quot; , Iq : Dies ist der Ruhestrom, also der Stromverbrauch des ICs. &lt;br /&gt;
*... &amp;quot;Voltage Drift&amp;quot;,  : Gibt an wie sehr sich eine Spannung bei Änderung der Temperatur ändert.&lt;br /&gt;
&lt;br /&gt;
* ... &amp;quot;Temperature coefficient&amp;quot; bezeichnet ebenfalls die Temperaturabhängigkeit, allerdings hier relativ zum Normalwert.&lt;br /&gt;
* ... &amp;quot;Leakage Current&amp;quot; : Dies ist ein Leckstrom, also ein Strom wo das Bauteil im Idealfall sperren soll. Besonders bei höherer Temperatur sperren Halbleiter aber nicht perfekt, und es fließt trotzdem ein kleiner Strom. Meist wird nur eine obere Grenze angegeben, und der tatsächlicher Wert ist meist deutlich kleiner.&lt;br /&gt;
&lt;br /&gt;
===Typical Applications===&lt;br /&gt;
Unter diesem Punkt werden schließlich typische Schaltungen mit dem Bauteil aufgeführt. In der Regel findet man dabei die Grundschaltung auf die sich die Daten weiter oben beziehen. Teils sind hier aber auch andere teils reicht interessante Schaltungen zu finden, die zeigen was man noch alles mit dem IC machen kann. In der Regel sind die Schaltungen ganz brauchbar. Das heißt aber nicht, dass die gezeigte Schaltungen optimal sind - nicht selten gibt es andere passendere oder günstigere Bauteile. &lt;br /&gt;
&lt;br /&gt;
Neben der reinen Schaltung finden sich teils auch noch Informationen zur Auslegung der Schaltung, also wie man die anderen Bauteile wie Kondensatoren oder Widerstände auslegen sollte. Bei der verlinkten Version für den 7805 ist hier allerdings fast nichts zu finden. Der 7805 ist eben relativ unkritisch - außer der hier in den Beispielen fehlenden Diode zwischen Ausgang und Eingang, die verhindert dass die Spannung am Ausgang deutlich größer wird als am Eingang.  &lt;br /&gt;
&lt;br /&gt;
Zu einigen Bauteilen bieten die Webseiten der Hersteller noch zusätzliche Informationen als sogenannte &amp;quot;Application Notes&amp;quot; an. Hier finden sich teils ausführlich beschriebene Schaltungen und nützliche Tipps zu den Bauteilen. Gerade hinsichtlich dieser zusätzlichen Informationen lohnt es sich bei mehr als einem Hersteller zu suchen.&lt;br /&gt;
&lt;br /&gt;
{{Ausbauwunsch| Erklärung von Kennlinien, App-Note's... Alles möglichst anfängertauglich erklären}}&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20481</id>
		<title>Datenblätter lesen und verstehen</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20481"/>
				<updated>2012-08-04T03:11:35Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Typical Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Über diesen Artikel==&lt;br /&gt;
!!!Dieser Artikel ist noch in Arbeit!!!&lt;br /&gt;
&lt;br /&gt;
In der Elektronik und/oder Robotik kommt man ohne Datenblätter (engl. datasheet) nicht wirklich weit. Nicht jeder Hobby-Bastler hatte eine Ausbildung im Elektrobereich&lt;br /&gt;
oder kann sich auf  Anhieb mit den Datenblättern anfreunden. Deswegen sollte dieser Artikel als kleine Hilfe zum Einstieg in die umfangreiche Bibliothek der Datenblätter dienen. Es muss auch erwähnt werden, dass in diesem Artikel kein Datenblatt bis ins kleinste Detail erklärt wird.&lt;br /&gt;
&lt;br /&gt;
==Nutzen von Datenblättern==&lt;br /&gt;
Datenblätter sind nicht nur bei Neuentwicklungen, sondern auch bei bestehender Hardware sehr nützlich. Anhand dieser nützlichen, meistens im PDF-Format verfügbaren Dokumenten, kann man für seine Projekt passende Bauteile verwenden ohne einen Fehlkauf zu tätigen oder das Bauteil zu zerstören. Aber auch bei der Fehlersuche  sind die Datenblätter sehr nützlich. Anhand der Information, die darin steht, kann man Eingangs- und Ausgangssignale bestimmen, das gemessene Signal mit dem erwarteten Signal vergleichen, ob das Bauteil den richtigen Strom verbraucht oder doch etwas mehr, was auf einen Kurzschluss deuten könnte.&lt;br /&gt;
&lt;br /&gt;
==Quellen==&lt;br /&gt;
Es gibt eine ziemlich überschaubare Anzahl von Quellen, woher man seine Datenblätter beziehen kann.&lt;br /&gt;
*Direkt im Online-Shop, wo man seine Elektronikteile gekauft hat oder kaufen kann. (Download in Artikel-Beschreibung)&lt;br /&gt;
*Diverse Datenbänke (z.B. [http://www.datasheetcatalog.com.de www.datasheetcatalog.com])&lt;br /&gt;
*Datenkataloge in Papierform (etwas veraltete Methode)&lt;br /&gt;
*Von der Website des Herstellers &lt;br /&gt;
&lt;br /&gt;
Gängige ICs wie der Spannungsregler 7805 werden teils von mehrere Herstellern gefertigt, so dass man ggf. auch mehrere Datenblätter (mit teils deutlich unterschiedlichem Umfang) zur Auswahl hat.&lt;br /&gt;
&lt;br /&gt;
==Angaben in Datenblättern==&lt;br /&gt;
Um die Angaben in Datenblättern anhand von Beispielen zu erklären, wurden folgende Beispiel-Bauteile ausgewählt.&lt;br /&gt;
*7805 Spannungsregler&lt;br /&gt;
*LED&lt;br /&gt;
*LDR&lt;br /&gt;
*ULN2804 Treiber&lt;br /&gt;
===Erste Seite===&lt;br /&gt;
In den meisten Fällen ist ein kurzer Blick auf die erste Seite schon ausreichend um die wesentlich Kenndaten im Groben zu erfahren. Aber auch hier kriegen manche schon Panik. Grund dafür ist oft die Marketing-Sprache. Das sollte aber einen nicht abschrecken. Es nimmt einem niemand übel, wenn man noch ein Fenster mit leo.org offen hat.&lt;br /&gt;
&lt;br /&gt;
Die groben Daten ganz am Anfang sind aber auch mit Vorsicht zu sehen: das sind teils Werbeaussagen, die nur unter bestimmten günstigen Bedingungen (z.B. niedrige Temperatur) gültig sind.&lt;br /&gt;
&lt;br /&gt;
Schauen wir doch mal in das Datenblatt von dem Festspannungsregler 7805 ([http://www.datasheetcatalog.org/datasheets/228/390068_DS.pdf Link zum Datenblatt])&lt;br /&gt;
Angaben auf der ersten Seite&lt;br /&gt;
&lt;br /&gt;
===Absolute Maximum Ratings===&lt;br /&gt;
Diesen Abschnitt findet man in fast jedem Datenblatt zu elektronischen Bauteilen. Hier wird aufgeführt was das Bauteil vertragen kann, also so etwas wie garantierte Maximalwerte für Spannung, Strom, Temperatur oder Verlustleistung. Bei den Grenzwerten ist nur garantiert, dass das Bauteil nicht kurzfristig kaputt geht - es ist nicht garantiert das bei den Bedingungen die normale Funktion noch gegeben ist. Auch kann eine dauerhafte Belastung bis zum Grenzwert zu einer relativ kurzen Lebensdauer führen.&lt;br /&gt;
&lt;br /&gt;
Die Parameter Absolute Maximum Ratings sind am wichtigsten für alle Bauteile und müssen so angehalten werden, dass keiner davon überschritten wird, weil das meistens zur Zerstörung des Bauteils führt. Zur sicherer Zerstörung jedes Bauteils führt Wärmeentwicklung im Gehause und überschritten der inneren Temperatur des Halbleiters ca. 150 °C. Je besser die Wärme in die Umgebung durch Kühlkörper abgeführt wird um so mehr Wärme darf entstehen. Das heisst, das die Nutzliche Verlustleistung bei 25 °C des Gehäuses und nicht der Umgebung bedeutet. Beispielweise für den Transistor BU508 ist die Verlustleistung 125 W bei Gehäusetemperatur 25 °C und 0 W bei 150 °C. Praktisch kann man ohne Lüfterkühlung und riesiegen Kühlkörper ca. 1/3 der max. Verlustleitung nutzen.&lt;br /&gt;
&lt;br /&gt;
Für das Beispiel 7805 finden sich im Datenblatt eher wenige Daten zur Temperatur und der maximalen Spannung, denn das IC besitzt einen internen Schutz gegen so etwas wie eine zu hohe Verlustleistung oder zu viel Strom am Ausgang. Die Angaben zum Wärmewiderstand, die die im verlinkten Datenblatt zu finden sind, gehören streng genommen wo anders hin.&lt;br /&gt;
&lt;br /&gt;
===Electrical Characteristics===&lt;br /&gt;
In diesem Abschnitt werden die wichtigsten Kenndaten angegeben. Hier wird also erklärt wie sich das IC verhalten sollte und mit welchen Abweichungen vom Idealfall man rechnen muss. Ganz am Anfang stehen üblicherweise die Randbedingungen wie Temperatur, Versorgungsspannung und ggf. die Schaltung für die die Daten gelten. Diese Werte kann man oft als Empfehlung für die Versorgungsspannung oder ähnliches sehen. Für die einzelnen Parameter werden dann meist minimale, maximale und typischen Werte angegeben. &lt;br /&gt;
&lt;br /&gt;
Eine Schwierigkeit für den Anfänger es ist dabei die Bedeutung der Parameter zu verstehen, bzw. in der oft langen Tabelle den richtigen zu finden. Einige spezielle Parameter werden ggf. im Datenblatt definiert, die meisten der aber einfach nur mit englischem Namen und Symbol angegeben. Als Hilfe kann hier z.B. die englische Version von Wikipedia dienen - oft sind da die englischen Parameter erklärt.  &lt;br /&gt;
&lt;br /&gt;
Statt als Zahlenwert in der Tabelle werden einige Eigenschaften dann im folgenden Abschnitt als Kurve bzw. Kennlinie angegeben. Wenn auch weniger genau als die Zahlenwerte, enthalten die Kurven oft deutlich mehr Informationen über das Verhalten der ICs.&lt;br /&gt;
&lt;br /&gt;
==== Parameter ====&lt;br /&gt;
Hier eine kurze Liste der häufiger vorkommenden Parameter, mit einer kurzen Erklärung:&lt;br /&gt;
*&amp;quot;Junction Temperature&amp;quot; : Dies ist die Temperatur des aktiven Teils im Halbleiter. Sie ist um das Produkt aus Verlustleistung und Wärmewiderstand (thermal resistance) höher als die des Gehäuses.  &lt;br /&gt;
*&amp;quot;Quiescent Current&amp;quot; , Iq : Dies ist der Ruhestrom, also der Stromverbrauch des ICs. &lt;br /&gt;
*... &amp;quot;Voltage Drift&amp;quot;,  : Gibt an wie sehr sich eine Spannung bei Änderung der Temperatur ändert.&lt;br /&gt;
&lt;br /&gt;
* ... &amp;quot;Temperature coefficient&amp;quot; bezeichnet ebenfalls die Temperaturabhängigkeit, allerdings hier relativ zum Normalwert.&lt;br /&gt;
* ... &amp;quot;Leakage Current&amp;quot; : Dies ist ein Leckstrom, also ein Strom wo das Bauteil im Idealfall sperren soll. Besonders bei höherer Temperatur sperren Halbleiter aber nicht perfekt, und es fließt trotzdem ein kleiner Strom. Meist wird nur eine obere Grenze angegeben, und der tatsächlicher Wert ist meist deutlich kleiner.&lt;br /&gt;
&lt;br /&gt;
===Typical Applications===&lt;br /&gt;
Unter diesem Punkt werden schließlich typische Schaltungen mit dem Bauteil aufgeführt. In der Regel findet man dabei die Grundschaltung auf die sich die Daten weiter oben beziehen. Teils sind hier aber auch andere teils reicht interessante Schaltungen zu finden, die zeigen was man noch alles mit dem IC machen kann. In der Regel sind die Schaltungen ganz brauchbar. Das heißt aber nicht, dass die gezeigte Schaltungen optimal sind - nicht selten gibt es andere passendere oder günstigere Bauteile. &lt;br /&gt;
&lt;br /&gt;
Neben der reinen Schaltung finden sich teils auch noch Informationen zur Auslegung der Schaltung, also wie man die anderen Bauteile wie Kondensatoren oder Widerstände auslegen sollte. Bei der verlinkten Version für den 7805 ist hier allerdings fast nichts zu finden. Der 7805 ist eben relativ unkritisch - außer der hier in den Beispielen fehlenden Diode zwischen Ausgang und Eingang, die verhindert dass die Spannung am Ausgang deutlich größer wird als am Eingang.  &lt;br /&gt;
&lt;br /&gt;
Zu einigen Bauteilen bieten die Webseiten der Hersteller noch zusätzliche Informationen als sogenannte &amp;quot;Application Notes&amp;quot; an. Hier finden sich teils ausführlich beschriebene Schaltungen und nützliche Tipps zu den Bauteilen. Gerade hinsichtlich dieser zusätzlichen Informationen lohnt es sich bei mehr als einem Hersteller zu suchen.&lt;br /&gt;
&lt;br /&gt;
{{Ausbauwunsch| Erklärung von Kennlinien, App-Note's... Alles möglichst anfängertauglich erklären}}&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20480</id>
		<title>Datenblätter lesen und verstehen</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20480"/>
				<updated>2012-08-04T02:53:34Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Parameter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Über diesen Artikel==&lt;br /&gt;
!!!Dieser Artikel ist noch in Arbeit!!!&lt;br /&gt;
&lt;br /&gt;
In der Elektronik und/oder Robotik kommt man ohne Datenblätter (engl. datasheet) nicht wirklich weit. Nicht jeder Hobby-Bastler hatte eine Ausbildung im Elektrobereich&lt;br /&gt;
oder kann sich auf  Anhieb mit den Datenblättern anfreunden. Deswegen sollte dieser Artikel als kleine Hilfe zum Einstieg in die umfangreiche Bibliothek der Datenblätter dienen. Es muss auch erwähnt werden, dass in diesem Artikel kein Datenblatt bis ins kleinste Detail erklärt wird.&lt;br /&gt;
&lt;br /&gt;
==Nutzen von Datenblättern==&lt;br /&gt;
Datenblätter sind nicht nur bei Neuentwicklungen, sondern auch bei bestehender Hardware sehr nützlich. Anhand dieser nützlichen, meistens im PDF-Format verfügbaren Dokumenten, kann man für seine Projekt passende Bauteile verwenden ohne einen Fehlkauf zu tätigen oder das Bauteil zu zerstören. Aber auch bei der Fehlersuche  sind die Datenblätter sehr nützlich. Anhand der Information, die darin steht, kann man Eingangs- und Ausgangssignale bestimmen, das gemessene Signal mit dem erwarteten Signal vergleichen, ob das Bauteil den richtigen Strom verbraucht oder doch etwas mehr, was auf einen Kurzschluss deuten könnte.&lt;br /&gt;
&lt;br /&gt;
==Quellen==&lt;br /&gt;
Es gibt eine ziemlich überschaubare Anzahl von Quellen, woher man seine Datenblätter beziehen kann.&lt;br /&gt;
*Direkt im Online-Shop, wo man seine Elektronikteile gekauft hat oder kaufen kann. (Download in Artikel-Beschreibung)&lt;br /&gt;
*Diverse Datenbänke (z.B. [http://www.datasheetcatalog.com.de www.datasheetcatalog.com])&lt;br /&gt;
*Datenkataloge in Papierform (etwas veraltete Methode)&lt;br /&gt;
*Von der Website des Herstellers &lt;br /&gt;
&lt;br /&gt;
Gängige ICs wie der Spannungsregler 7805 werden teils von mehrere Herstellern gefertigt, so dass man ggf. auch mehrere Datenblätter (mit teils deutlich unterschiedlichem Umfang) zur Auswahl hat.&lt;br /&gt;
&lt;br /&gt;
==Angaben in Datenblättern==&lt;br /&gt;
Um die Angaben in Datenblättern anhand von Beispielen zu erklären, wurden folgende Beispiel-Bauteile ausgewählt.&lt;br /&gt;
*7805 Spannungsregler&lt;br /&gt;
*LED&lt;br /&gt;
*LDR&lt;br /&gt;
*ULN2804 Treiber&lt;br /&gt;
===Erste Seite===&lt;br /&gt;
In den meisten Fällen ist ein kurzer Blick auf die erste Seite schon ausreichend um die wesentlich Kenndaten im Groben zu erfahren. Aber auch hier kriegen manche schon Panik. Grund dafür ist oft die Marketing-Sprache. Das sollte aber einen nicht abschrecken. Es nimmt einem niemand übel, wenn man noch ein Fenster mit leo.org offen hat.&lt;br /&gt;
&lt;br /&gt;
Die groben Daten ganz am Anfang sind aber auch mit Vorsicht zu sehen: das sind teils Werbeaussagen, die nur unter bestimmten günstigen Bedingungen (z.B. niedrige Temperatur) gültig sind.&lt;br /&gt;
&lt;br /&gt;
Schauen wir doch mal in das Datenblatt von dem Festspannungsregler 7805 ([http://www.datasheetcatalog.org/datasheets/228/390068_DS.pdf Link zum Datenblatt])&lt;br /&gt;
Angaben auf der ersten Seite&lt;br /&gt;
&lt;br /&gt;
===Absolute Maximum Ratings===&lt;br /&gt;
Diesen Abschnitt findet man in fast jedem Datenblatt zu elektronischen Bauteilen. Hier wird aufgeführt was das Bauteil vertragen kann, also so etwas wie garantierte Maximalwerte für Spannung, Strom, Temperatur oder Verlustleistung. Bei den Grenzwerten ist nur garantiert, dass das Bauteil nicht kurzfristig kaputt geht - es ist nicht garantiert das bei den Bedingungen die normale Funktion noch gegeben ist. Auch kann eine dauerhafte Belastung bis zum Grenzwert zu einer relativ kurzen Lebensdauer führen.&lt;br /&gt;
&lt;br /&gt;
Die Parameter Absolute Maximum Ratings sind am wichtigsten für alle Bauteile und müssen so angehalten werden, dass keiner davon überschritten wird, weil das meistens zur Zerstörung des Bauteils führt. Zur sicherer Zerstörung jedes Bauteils führt Wärmeentwicklung im Gehause und überschritten der inneren Temperatur des Halbleiters ca. 150 °C. Je besser die Wärme in die Umgebung durch Kühlkörper abgeführt wird um so mehr Wärme darf entstehen. Das heisst, das die Nutzliche Verlustleistung bei 25 °C des Gehäuses und nicht der Umgebung bedeutet. Beispielweise für den Transistor BU508 ist die Verlustleistung 125 W bei Gehäusetemperatur 25 °C und 0 W bei 150 °C. Praktisch kann man ohne Lüfterkühlung und riesiegen Kühlkörper ca. 1/3 der max. Verlustleitung nutzen.&lt;br /&gt;
&lt;br /&gt;
Für das Beispiel 7805 finden sich im Datenblatt eher wenige Daten zur Temperatur und der maximalen Spannung, denn das IC besitzt einen internen Schutz gegen so etwas wie eine zu hohe Verlustleistung oder zu viel Strom am Ausgang. Die Angaben zum Wärmewiderstand, die die im verlinkten Datenblatt zu finden sind, gehören streng genommen wo anders hin.&lt;br /&gt;
&lt;br /&gt;
===Electrical Characteristics===&lt;br /&gt;
In diesem Abschnitt werden die wichtigsten Kenndaten angegeben. Hier wird also erklärt wie sich das IC verhalten sollte und mit welchen Abweichungen vom Idealfall man rechnen muss. Ganz am Anfang stehen üblicherweise die Randbedingungen wie Temperatur, Versorgungsspannung und ggf. die Schaltung für die die Daten gelten. Diese Werte kann man oft als Empfehlung für die Versorgungsspannung oder ähnliches sehen. Für die einzelnen Parameter werden dann meist minimale, maximale und typischen Werte angegeben. &lt;br /&gt;
&lt;br /&gt;
Eine Schwierigkeit für den Anfänger es ist dabei die Bedeutung der Parameter zu verstehen, bzw. in der oft langen Tabelle den richtigen zu finden. Einige spezielle Parameter werden ggf. im Datenblatt definiert, die meisten der aber einfach nur mit englischem Namen und Symbol angegeben. Als Hilfe kann hier z.B. die englische Version von Wikipedia dienen - oft sind da die englischen Parameter erklärt.  &lt;br /&gt;
&lt;br /&gt;
Statt als Zahlenwert in der Tabelle werden einige Eigenschaften dann im folgenden Abschnitt als Kurve bzw. Kennlinie angegeben. Wenn auch weniger genau als die Zahlenwerte, enthalten die Kurven oft deutlich mehr Informationen über das Verhalten der ICs.&lt;br /&gt;
&lt;br /&gt;
==== Parameter ====&lt;br /&gt;
Hier eine kurze Liste der häufiger vorkommenden Parameter, mit einer kurzen Erklärung:&lt;br /&gt;
*&amp;quot;Junction Temperature&amp;quot; : Dies ist die Temperatur des aktiven Teils im Halbleiter. Sie ist um das Produkt aus Verlustleistung und Wärmewiderstand (thermal resistance) höher als die des Gehäuses.  &lt;br /&gt;
*&amp;quot;Quiescent Current&amp;quot; , Iq : Dies ist der Ruhestrom, also der Stromverbrauch des ICs. &lt;br /&gt;
*... &amp;quot;Voltage Drift&amp;quot;,  : Gibt an wie sehr sich eine Spannung bei Änderung der Temperatur ändert.&lt;br /&gt;
&lt;br /&gt;
* ... &amp;quot;Temperature coefficient&amp;quot; bezeichnet ebenfalls die Temperaturabhängigkeit, allerdings hier relativ zum Normalwert.&lt;br /&gt;
* ... &amp;quot;Leakage Current&amp;quot; : Dies ist ein Leckstrom, also ein Strom wo das Bauteil im Idealfall sperren soll. Besonders bei höherer Temperatur sperren Halbleiter aber nicht perfekt, und es fließt trotzdem ein kleiner Strom. Meist wird nur eine obere Grenze angegeben, und der tatsächlicher Wert ist meist deutlich kleiner.&lt;br /&gt;
&lt;br /&gt;
===Typical Applications===&lt;br /&gt;
Unter diesem Punkt werden schließlich typische Schaltungen mit dem Bauteil aufgeführt. In der Regel findet man dabei die Grundschaltung auf die sich die Daten weiter oben beziehen. Teils sind hier aber auch andere teils reicht interessante Schaltungen zu finden, die zeigen was man noch alles mit dem IC machen kann. In der Regel sind die Schaltungen ganz brauchbar. Das heißt aber nicht, dass die gezeigten Schaltungen eine gute Lösung sind - nicht selten gibt es andere passendere oder günstigere ICs. &lt;br /&gt;
&lt;br /&gt;
Neben der reinen Schaltung finden sich teils auch noch Informationen zur Auslegung der Schaltung, also wie man die anderen Bauteile wie Kondensatoren oder Widerstände auslegen sollten. Bei der verlinkten Version für den 7805 ist hier allerdings fast nichts zu finden - der 7805 ist allerdings auch relativ unkritisch - außer der hier in den Beispielen fehlenden Diode zwischen Ausgang und Eingang, die verhindert dass die Spannung am Ausgang deutlich größer wird als am Eingang. &lt;br /&gt;
&lt;br /&gt;
Zu einigen Bauteilen bieten die Webseiten der Hersteller noch zusätzliche Informationen als sogenannte &amp;quot;Application Notes&amp;quot; an. Hier finden sich teils ausführlich beschriebene Schaltungen und nützliche Tipps zu den Bauteilen. Gerade hinsichtlich dieser zusätzlichen Informationen lohnt es sich bei mehr als einem Hersteller zu suchen. &lt;br /&gt;
&lt;br /&gt;
{{Ausbauwunsch| Erklärung von Kennlinien, App-Note's... Alles möglichst anfängertauglich erklären}}&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20479</id>
		<title>Datenblätter lesen und verstehen</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Datenbl%C3%A4tter_lesen_und_verstehen&amp;diff=20479"/>
				<updated>2012-08-04T02:46:53Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Absolute Maximum Ratings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Über diesen Artikel==&lt;br /&gt;
!!!Dieser Artikel ist noch in Arbeit!!!&lt;br /&gt;
&lt;br /&gt;
In der Elektronik und/oder Robotik kommt man ohne Datenblätter (engl. datasheet) nicht wirklich weit. Nicht jeder Hobby-Bastler hatte eine Ausbildung im Elektrobereich&lt;br /&gt;
oder kann sich auf  Anhieb mit den Datenblättern anfreunden. Deswegen sollte dieser Artikel als kleine Hilfe zum Einstieg in die umfangreiche Bibliothek der Datenblätter dienen. Es muss auch erwähnt werden, dass in diesem Artikel kein Datenblatt bis ins kleinste Detail erklärt wird.&lt;br /&gt;
&lt;br /&gt;
==Nutzen von Datenblättern==&lt;br /&gt;
Datenblätter sind nicht nur bei Neuentwicklungen, sondern auch bei bestehender Hardware sehr nützlich. Anhand dieser nützlichen, meistens im PDF-Format verfügbaren Dokumenten, kann man für seine Projekt passende Bauteile verwenden ohne einen Fehlkauf zu tätigen oder das Bauteil zu zerstören. Aber auch bei der Fehlersuche  sind die Datenblätter sehr nützlich. Anhand der Information, die darin steht, kann man Eingangs- und Ausgangssignale bestimmen, das gemessene Signal mit dem erwarteten Signal vergleichen, ob das Bauteil den richtigen Strom verbraucht oder doch etwas mehr, was auf einen Kurzschluss deuten könnte.&lt;br /&gt;
&lt;br /&gt;
==Quellen==&lt;br /&gt;
Es gibt eine ziemlich überschaubare Anzahl von Quellen, woher man seine Datenblätter beziehen kann.&lt;br /&gt;
*Direkt im Online-Shop, wo man seine Elektronikteile gekauft hat oder kaufen kann. (Download in Artikel-Beschreibung)&lt;br /&gt;
*Diverse Datenbänke (z.B. [http://www.datasheetcatalog.com.de www.datasheetcatalog.com])&lt;br /&gt;
*Datenkataloge in Papierform (etwas veraltete Methode)&lt;br /&gt;
*Von der Website des Herstellers &lt;br /&gt;
&lt;br /&gt;
Gängige ICs wie der Spannungsregler 7805 werden teils von mehrere Herstellern gefertigt, so dass man ggf. auch mehrere Datenblätter (mit teils deutlich unterschiedlichem Umfang) zur Auswahl hat.&lt;br /&gt;
&lt;br /&gt;
==Angaben in Datenblättern==&lt;br /&gt;
Um die Angaben in Datenblättern anhand von Beispielen zu erklären, wurden folgende Beispiel-Bauteile ausgewählt.&lt;br /&gt;
*7805 Spannungsregler&lt;br /&gt;
*LED&lt;br /&gt;
*LDR&lt;br /&gt;
*ULN2804 Treiber&lt;br /&gt;
===Erste Seite===&lt;br /&gt;
In den meisten Fällen ist ein kurzer Blick auf die erste Seite schon ausreichend um die wesentlich Kenndaten im Groben zu erfahren. Aber auch hier kriegen manche schon Panik. Grund dafür ist oft die Marketing-Sprache. Das sollte aber einen nicht abschrecken. Es nimmt einem niemand übel, wenn man noch ein Fenster mit leo.org offen hat.&lt;br /&gt;
&lt;br /&gt;
Die groben Daten ganz am Anfang sind aber auch mit Vorsicht zu sehen: das sind teils Werbeaussagen, die nur unter bestimmten günstigen Bedingungen (z.B. niedrige Temperatur) gültig sind.&lt;br /&gt;
&lt;br /&gt;
Schauen wir doch mal in das Datenblatt von dem Festspannungsregler 7805 ([http://www.datasheetcatalog.org/datasheets/228/390068_DS.pdf Link zum Datenblatt])&lt;br /&gt;
Angaben auf der ersten Seite&lt;br /&gt;
&lt;br /&gt;
===Absolute Maximum Ratings===&lt;br /&gt;
Diesen Abschnitt findet man in fast jedem Datenblatt zu elektronischen Bauteilen. Hier wird aufgeführt was das Bauteil vertragen kann, also so etwas wie garantierte Maximalwerte für Spannung, Strom, Temperatur oder Verlustleistung. Bei den Grenzwerten ist nur garantiert, dass das Bauteil nicht kurzfristig kaputt geht - es ist nicht garantiert das bei den Bedingungen die normale Funktion noch gegeben ist. Auch kann eine dauerhafte Belastung bis zum Grenzwert zu einer relativ kurzen Lebensdauer führen.&lt;br /&gt;
&lt;br /&gt;
Die Parameter Absolute Maximum Ratings sind am wichtigsten für alle Bauteile und müssen so angehalten werden, dass keiner davon überschritten wird, weil das meistens zur Zerstörung des Bauteils führt. Zur sicherer Zerstörung jedes Bauteils führt Wärmeentwicklung im Gehause und überschritten der inneren Temperatur des Halbleiters ca. 150 °C. Je besser die Wärme in die Umgebung durch Kühlkörper abgeführt wird um so mehr Wärme darf entstehen. Das heisst, das die Nutzliche Verlustleistung bei 25 °C des Gehäuses und nicht der Umgebung bedeutet. Beispielweise für den Transistor BU508 ist die Verlustleistung 125 W bei Gehäusetemperatur 25 °C und 0 W bei 150 °C. Praktisch kann man ohne Lüfterkühlung und riesiegen Kühlkörper ca. 1/3 der max. Verlustleitung nutzen.&lt;br /&gt;
&lt;br /&gt;
Für das Beispiel 7805 finden sich im Datenblatt eher wenige Daten zur Temperatur und der maximalen Spannung, denn das IC besitzt einen internen Schutz gegen so etwas wie eine zu hohe Verlustleistung oder zu viel Strom am Ausgang. Die Angaben zum Wärmewiderstand, die die im verlinkten Datenblatt zu finden sind, gehören streng genommen wo anders hin.&lt;br /&gt;
&lt;br /&gt;
===Electrical Characteristics===&lt;br /&gt;
In diesem Abschnitt werden die wichtigsten Kenndaten angegeben. Hier wird also erklärt wie sich das IC verhalten sollte und mit welchen Abweichungen vom Idealfall man rechnen muss. Ganz am Anfang stehen üblicherweise die Randbedingungen wie Temperatur, Versorgungsspannung und ggf. die Schaltung für die die Daten gelten. Diese Werte kann man oft als Empfehlung für die Versorgungsspannung oder ähnliches sehen. Für die einzelnen Parameter werden dann meist minimale, maximale und typischen Werte angegeben. &lt;br /&gt;
&lt;br /&gt;
Eine Schwierigkeit für den Anfänger es ist dabei die Bedeutung der Parameter zu verstehen, bzw. in der oft langen Tabelle den richtigen zu finden. Einige spezielle Parameter werden ggf. im Datenblatt definiert, die meisten der aber einfach nur mit englischem Namen und Symbol angegeben. Als Hilfe kann hier z.B. die englische Version von Wikipedia dienen - oft sind da die englischen Parameter erklärt.  &lt;br /&gt;
&lt;br /&gt;
Statt als Zahlenwert in der Tabelle werden einige Eigenschaften dann im folgenden Abschnitt als Kurve bzw. Kennlinie angegeben. Wenn auch weniger genau als die Zahlenwerte, enthalten die Kurven oft deutlich mehr Informationen über das Verhalten der ICs.&lt;br /&gt;
&lt;br /&gt;
==== Parameter ====&lt;br /&gt;
Hier eine kurze Liste der häufiger vorkommenden Parameter, mit einer kurzen Erklärung:&lt;br /&gt;
*&amp;quot;Junction Temperature&amp;quot; : Dies ist die Temperatur des aktiven Teils im inneren des ICs. Sie ist um das Produkt aus Verlustleistung und Wärmewiderstand (thermal resistance) höher als die des Gehäuses.  &lt;br /&gt;
*&amp;quot;Quiescent Current&amp;quot; , Iq : Dies ist der Ruhestrom, also der Stromverbrauch des ICs. &lt;br /&gt;
*... &amp;quot;Voltage Drift&amp;quot;,  : Gibt an wie sehr sich eine Spannung bei Änderung der Temperatur ändert.&lt;br /&gt;
&lt;br /&gt;
* ... &amp;quot;Temperature coefficient&amp;quot; bezeichnet ebenfalls die Temperaturabhängigkeit, allerdings hier relativ zum Normalwert.&lt;br /&gt;
* ... &amp;quot;Leakage Current&amp;quot; : Dies ist ein Leckstrom, also ein Strom wo das Bauteil im Idealfall sperren soll. Besonders bei höherer Temperatur sperren Halbleiter aber nicht perfekt, und es fließt trotzdem ein kleiner Strom. Meist wird nur eine obere Grenze angegeben, und der tatsächlicher Wert ist meist deutlich kleiner.&lt;br /&gt;
&lt;br /&gt;
===Typical Applications===&lt;br /&gt;
Unter diesem Punkt werden schließlich typische Schaltungen mit dem Bauteil aufgeführt. In der Regel findet man dabei die Grundschaltung auf die sich die Daten weiter oben beziehen. Teils sind hier aber auch andere teils reicht interessante Schaltungen zu finden, die zeigen was man noch alles mit dem IC machen kann. In der Regel sind die Schaltungen ganz brauchbar. Das heißt aber nicht, dass die gezeigten Schaltungen eine gute Lösung sind - nicht selten gibt es andere passendere oder günstigere ICs. &lt;br /&gt;
&lt;br /&gt;
Neben der reinen Schaltung finden sich teils auch noch Informationen zur Auslegung der Schaltung, also wie man die anderen Bauteile wie Kondensatoren oder Widerstände auslegen sollten. Bei der verlinkten Version für den 7805 ist hier allerdings fast nichts zu finden - der 7805 ist allerdings auch relativ unkritisch - außer der hier in den Beispielen fehlenden Diode zwischen Ausgang und Eingang, die verhindert dass die Spannung am Ausgang deutlich größer wird als am Eingang. &lt;br /&gt;
&lt;br /&gt;
Zu einigen Bauteilen bieten die Webseiten der Hersteller noch zusätzliche Informationen als sogenannte &amp;quot;Application Notes&amp;quot; an. Hier finden sich teils ausführlich beschriebene Schaltungen und nützliche Tipps zu den Bauteilen. Gerade hinsichtlich dieser zusätzlichen Informationen lohnt es sich bei mehr als einem Hersteller zu suchen. &lt;br /&gt;
&lt;br /&gt;
{{Ausbauwunsch| Erklärung von Kennlinien, App-Note's... Alles möglichst anfängertauglich erklären}}&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=19691</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=19691"/>
				<updated>2012-05-21T16:46:16Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Multitasking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich. Bei PIC's ist echtes Multitasking (Parallellaufen) nur mit Timer und ADC Wandler möglich (siehe dazu: http://www.roboternetz.de/community/threads/42200-Frequenzz%C3%A4hler-mit-LPH2673-1-%28zum-Nachbauen%29?highlight=LPH2673-1 ) &lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende realisiert. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer unterbrochen und nächster Tast gestartet. Dafür muss immer nach Beenden der ISR unbedingt ins HP gesprungen werden und die Adresse vom PC, wo der Task unterbrochen wurde auf dem Stapel gespeichert werden. Wenn die Zeit für den unterbrochenen Task wieder kommt, wird er ab der unterbrochenen Stelle wieder in der ihn zustehenden Zeit ausgeführt, wieder unterbrochen u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=19690</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=19690"/>
				<updated>2012-05-21T16:36:40Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Multitasking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich. Bei PIC's ist echtes Multitasking (Parallellaufen) nur mit Timer und ADC Wandler möglich. &lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende realisiert. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer unterbrochen und nächster Tast gestartet. Dafür muss immer nach Beenden der ISR unbedingt ins HP gesprungen werden und die Adresse vom PC, wo der Task unterbrochen wurde auf dem Stapel gespeichert werden. Wenn die Zeit für den unterbrochenen Task wieder kommt, wird er ab der unterbrochenen Stelle wieder in der ihn zustehenden Zeit ausgeführt, wieder unterbrochen u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Schwingquarz&amp;diff=18864</id>
		<title>Schwingquarz</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Schwingquarz&amp;diff=18864"/>
				<updated>2012-01-26T09:11:01Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Temperaturabhängigkeit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Schaltzeichen_Quarz.jpg|thumb|Schaltzeichen eines Schwingquarz]]&lt;br /&gt;
Ein Schwingquarz ist ein kleines Plättchen, in einer bestimmten Form aus einem speziellem Quarzkristall geschnitten. Dieses Plättchen erhält zwei Kontakte und wird so in ein luftdichtes Gehäuse montiert, daß es nur durch diese Anschlüsse gehalten wird.&lt;br /&gt;
&lt;br /&gt;
Auf Grund der piezo-elektrischen Eigenschaften des Quarzes führt dieser unter dem Einfluß von elektrischen Wechselspannungen genau definierte Schwingungen aus, wenn die Frequenz der Wechselspannung mit der Eigenfrequenz des Quarzes übereinstimmt. Elektrisch verhält sich der Quarz dann wie ein Schwingkreis mit hoher Güte. Durch externe Kondesatoren kann die Frequenz ein wenig (bis ca. 0,01 %) verändert werden&lt;br /&gt;
&lt;br /&gt;
Für Frequenzen bis etwa 100 MHz sind häufig Grundtonquarze verfügbar. Für höhere Frequenzen (über etwa 20 MHz) werden zum Teil aber auch Obertonquarze angeboten. Die gewünschte Frequenz ist bei diesen Schwingquarzen nicht die niedriegste verfügbare Frequenz (der Grundton), sondern ein ungerades Vielfaches davon (üblich ist das 3- oder 5-Fache, ein Oberton). Durch einen zusätzlichen Schwingkreis muß dann die richtige Resoanzfrequenz ausgewählt werden. Zum direkten Anschluß an Mikrocontroller benötigt man Grundtonquarze.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Schwingquarze kommen überall zur Anwendung, wo eine konstante Frequenz (u.a. als Zeitbasis) gebraucht wird. Sie finden sich z. B. in praktisch allen Sendern, in Quarzuhren, als Taktgeber in allen Arten von Computern sowie in Frequenzzählern und digitalen Signalgeneratoren.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
[[Bild:Quarze.jpg|thumb|Bauformen verschiedener Schwingquarze und externer Quarzoszillatoren]]&lt;br /&gt;
Der folgende Kommentar ist eigentlich überflüssig, aber gerade dies wird oft fasch verstanden:&amp;lt;br/&amp;gt;'''Ein Schwingquarz alleine bestimmt nur die Frequenz. Er ist weder ein Oszillator noch ein Taktgeber!'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Allgemeines zu Schwingquarzen ==&lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|Für die meisten Verwendungszwecke sind die im Handel erhältlichen Schwingquarze sowie deren Verwendung in den üblichen Oszillatorschaltungen (siehe [[Quarzoszillator]]) völlig ausreichend. Bei speziellen Anforderungen oder dem Entwurf neuer Schaltungen sollte auf jeden Fall vor der Verwendung eines Quarzes das entsprechende Datenblatt des Herstellers zu Rate gezogen werden!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Temperaturabhängigkeit ===&lt;br /&gt;
Schwingquarze ändern ihr Verhalten und damit auch ihre elektrischen Eigenschaften in Abhängigkeit von der Temperatur. Die Abweichung liegt je nach Qualität bei z.B. 0,2ppm pro °C (aber nicht linear). In der Praxis bedeutet dies im Temperaturbereich von -40°C bis +85°C (Verwendung &amp;quot;normaler&amp;quot; Bauelemente) eine Abweichung von maximal 0,01 % von der nominellen Frequenz. Die ist für die meisten Verwendungszwecke völlig ausreichend!&amp;lt;br/&amp;gt;Für Funkfrequenzeinstellungen und hochgenaue Uhren kann durch die Wahl geeigneter externer Bauelemente eine Korrektur dieses Temperaturverhaltens durchgeführt werden. Alternativ wird die Temperatur konstant gehalten auf z.B. 40°C. Am stabilsten bei variabler Temperatur sind Quarze 7,2 MHz.&lt;br /&gt;
&lt;br /&gt;
=== Leistungsverhalten ===&lt;br /&gt;
*Großleistungsverhalten: Die Amplituden der Schwingungen im Quarzkristall sind proportional zu dem Wechselstrom, der durch den Resonanzwiderstand (Verlustwiderstand) des Quarzes fließt. Steigt dieser Strom stark an, kommt es zuerst zu Änderungen in den elastischen Eigenschaften des Quarzes, danach zu starker Erwärmung durch die Verlustleistung im Resonanzwiderstand. Beide Situationen führen zu bleibenden Veränderungen der Resonanzfrequenz. Steigt der Strom weiter, wird der Quarz nach Überschreiten der inneren Festigkeit des Kristallgitters zerstört.&amp;lt;br/&amp;gt; Quarze mit kleinen Oberflächen oder mit kleinen Elektroden (SMD) sind weniger belastbar wie größere Quarze. Quarze mit großer Güte Q sind ebenfalls weniger belastbar wie Quarze mit kleiner Güte.&lt;br /&gt;
*Kleinleistungsverhalten: Auf Grund von Fertigungstoleranzen und -fehlern kann es im Bereich kleinster Belastungen (unter 1mW) eines Quarzes zu teils gravierenden Abweichungen des Resonanzwiderstandes kommen. Dies zeigt sich häufig in einem schwachen oder gar fehlenden Anschwingen des Quarzoszillators im unbelasteten Zustand. Ein solcher Quarz ist definitv ein Produktionsfehler.&amp;lt;br/&amp;gt;Der Anwender eines solchen Quarzes kann entweder seine Schaltung überarbeiten (Anschwingen unter größerer Last), oder den Quarz austauschen.&lt;br /&gt;
&lt;br /&gt;
=== Alterung ===&lt;br /&gt;
Durch das verwendete Material sowie durch die verwendeten konstruktions- und herstellungsbedingten Verfahren verändert sich die Resonanzfrequenz eines Schwingquarzes kontinuierlich über einen längeren Zeitraum, der Quarz &amp;quot;altert&amp;quot;. Auch ist diese Alterung temperaturabhängig, bei hohen oder niedrigen Temperaturen altert ein Quarz schneller. Hierbei beträgt die Zunahme der Alterung etwa 10% pro 10°C, bei 85°C altert ein Quarz etwa doppelt so schnell wie bei 25°C.&amp;lt;br/&amp;gt;Die Alterungsrate bei typischen Großserien-Quarzen liegt im Bereich von etwa 2ppm pro Jahr. Diese Alterung ist also für normale Anwendungegebiete vernachlässigbar, für hochgenaue Anwendungen können stabilisierte Schwingquarze mit einer Alterungrate von unter 0,1ppm pro Jahr eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Uhrenquarze ===&lt;br /&gt;
Speziell für Anwendungen mit sehr geringer Leistungsaufnahmen gibt es Quarze für die relativ niedrige Frequenz von 32678 Hz. Diese sind intern in Form einer Stimmgabel aufgebaut, verhalten sich aber sonst ähnlich wie die plattenförmigen Quarze.&lt;br /&gt;
&lt;br /&gt;
== Verweise ==&lt;br /&gt;
siehe auch [[Quarzoszillator]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
* [http://www.s-t-e.de/index.html?http%3A//www.s-t-e.de/content/Tables/Tables_06.html Das Quarz-Glossar]&lt;br /&gt;
* [http://www.qsl.net/dk1ag/buch.html Das Grosse Quarzkochbuch]&lt;br /&gt;
* [http://www.wikipedia.de Wikipedia]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Anmerkung ==&lt;br /&gt;
''Der Autor möchte hier weder die an anderen Stellen zu findenden Formelsammlungen wiedergeben, noch mit diesem Artikel ein Fachbuch ersetzten. Einzig die Grundlagen, die (aus eigener Erfahrung) für einen Hobby-Bastler von Interesse sind, sollen hier dargestellt werden.''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Autor ==&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Williwilli|Williwilli]] 10:45, 15. Aug 2008 (CET)&lt;br /&gt;
&lt;br /&gt;
 [[Kategorie:Grundlagen]]&lt;br /&gt;
 [[Kategorie:Elektronik]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Wunschthemen&amp;diff=18863</id>
		<title>Wunschthemen</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Wunschthemen&amp;diff=18863"/>
				<updated>2012-01-26T09:07:16Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Meine Wunschthemen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Auf dieser Seite kann '''jeder''' Themen nennen, die er sich in diesem Wiki wünschen würde. Die Seite dient Usern, die gerne was schreiben möchten, als Anregung. Hat jemand ein entsprechendes Thema erstellt, kann er es auch aus dieser Liste wieder streichen. &lt;br /&gt;
&lt;br /&gt;
==Meine Wunschthemen==&lt;br /&gt;
&lt;br /&gt;
'''Allgemeines'''&lt;br /&gt;
* Spracherkennung&lt;br /&gt;
* [[Schaltung AVR-Digitizer]] um Videobild mit AVR zu digitalisieren und auszuwerten oder per Funk zu übertragen - etwas zu viel verlangt, das geht kaum.&lt;br /&gt;
* Ausführliche Bedienhinweise für Euroflex-Saugroboter Monster Intelligente F1&lt;br /&gt;
* Künstliche Neuronale Netze&lt;br /&gt;
* [[Formula Flowcode Buggy]]&lt;br /&gt;
* Wie ist eine Grundschaltung für einen Roboter aufgebaut, dh. wie werden Motoren mit AVR's angesteuert, wie Sensoren ausgelesen? etc.&lt;br /&gt;
* Ausführliche Eagle Tutorials&lt;br /&gt;
* Roboterarm ( Allgemeines, Aufbau, Dimensionierung, Berechnung, Beispiele, usw.)&lt;br /&gt;
* Polyethylenterephthalat (PET)&lt;br /&gt;
* AVR Bilderkennung &lt;br /&gt;
*** Taster-Abfragen und damit Interrupt-Routinen auslösen insbesondere AVR Atmega32 - RN Control&lt;br /&gt;
* Bewegungserkennung und Verfolgung mit AVR und Kamera&lt;br /&gt;
&lt;br /&gt;
'''Programmierung'''&lt;br /&gt;
* Grundlagen und Programm (z.B. in GCC) für eine(n) Morse-Code-Sender/-Empfänger/-Station&lt;br /&gt;
*Wie wär's mit einem Artikel über das Programm [[TuxMinds]] [http://sourceforge.net/projects/tuxminds]. Damit kann man aus Bausteinen sein eigenes Programm zusammenbauen, auf den Bot laden und laufen lassen. Eines der wenigen symbolgestützten Programmiertools für Linux. Das Ganze ist ziemlich offen und man kann diverse eigene Sachen einbauen. Die Doku ist allerdings noch etwas dünn. &lt;br /&gt;
*Wie programmiere ich meinen Atmelxx mit meinem Lieblingstool Eclipse? (gcc läuft bereits via cygwin)&amp;gt;&amp;gt;&amp;gt;&amp;gt;Woher bekomme ich die Header des Atmelxx und was muss noch beachtet werden?&lt;br /&gt;
*Funktionen(Unterprogramme) und Tasks(parallele Prozesse) in Bascom&lt;br /&gt;
* [[Network_Controller/PC_Praxis#Network_Controller.2FPC_RS232_mit_Windows|Ansprechen der RS232 Schnittstelle mit gängigen Programmiersprachen]]&lt;br /&gt;
* Pda und PPC steuerung über CF und MMC slot&lt;br /&gt;
* [[GCC]] Einführung mit Beispielen (welche Beispiele? Benutzung von GCC? (Optionen, ...)?, Programmbeispiele (also [[C-Tutorial]])?), für spezielle Maschinen oder Derivate? ANSI-C? Was fehlt in den [[:Kategorie:Quellcode C|C-Beispielen]]?)&lt;br /&gt;
* Mehr C Tutorials wie bei Bascom für LCDs,....&lt;br /&gt;
* C-Control 2 Tutorial&lt;br /&gt;
* PIC16F... Programmierung mit dem Go Embedded Pascal-Compiler&lt;br /&gt;
* [(ATMega128 mit eingelötetem Uhrenquarz)] Einstellung/Abfrage/Speichern von Zeit und Datum - Code für AVR Dude&lt;br /&gt;
* Ein Komplettes kleines Projekt: Kommunikation von einem Atmel µC(z.B.: AtMegaX) zum PC über USB &lt;br /&gt;
* Eine Anleitung zu Programmern wie z.b. Ponyprog und [[avrdude]]&lt;br /&gt;
* Quadrocopter - Programmierung in Bascom&lt;br /&gt;
&lt;br /&gt;
'''Hardware'''&lt;br /&gt;
* Arduino&lt;br /&gt;
* Serielles AVR-ISP Programmierkabel&lt;br /&gt;
* USB-ISP Programmieradaper&lt;br /&gt;
* JTAG mit AVRs&lt;br /&gt;
* Shift-/Schieberegister  - Einiges schon unter Portexpander am AVR &lt;br /&gt;
* Sensorschaltung Windrichtung&lt;br /&gt;
* Sensorschaltung Luftfeuchte&lt;br /&gt;
* Schaltungssicherheitsvorkehrungen (wenns nicht nur auf dem Basteltisch funktionieren soll)&lt;br /&gt;
** EMV&lt;br /&gt;
*** ESD-Sicherheit&lt;br /&gt;
*** ESD-Bauteile (Supressor Dioden, etc.)&lt;br /&gt;
*** EMV-konformes Routing&lt;br /&gt;
*** Abschirmung bei Leitungen, Gehäuseauswahl, etc.&lt;br /&gt;
* Bluetooth Support (senden/empfangen) nach dem Vorbild des Lego NXT&lt;br /&gt;
* Microcontroller Entwicklungsboards&lt;br /&gt;
* Oszilloskop bedienung und Einstellung für Anfänger&lt;br /&gt;
* Kühlung: Richtige Auslegung, Hinweise, Tipps - gerade auch für größere Leistungen&lt;br /&gt;
* Richtige Stromversorgung für den Bot (Schaltungen, Spannungsreglung, Auslegung, was ist zu beachten etc.)&lt;br /&gt;
** Anm.: Reicht der Artikel [[Spannungsregler]] hierfür nicht aus? Falls nein: welche Details fehlen / was genau soll erklärt werden?&lt;br /&gt;
&lt;br /&gt;
==Folgende erscheinen noch unvollständig und sollten von Usern die in dem Bereich kundig sind, ergänzt werden==&lt;br /&gt;
Findet man jetzt durch folgenden Link: [[:Kategorie:Artikelausbau]]&lt;br /&gt;
Artikel die unvollständig sind sollte man jetzt also nicht mehr hier aufgelistet werden, sondern die Artikel sollten am unteren Ende durch folgendes Kommando ergänzen werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
  {{Ausbauwunsch|Mehr Grundlagen und vor allem Programmbeispiele etc.}}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Artikel wird dann ein Hinweis eingeblendet, ähnlich wie diesem:&lt;br /&gt;
&lt;br /&gt;
[[Bild:artikelausbau.gif]]&lt;br /&gt;
&lt;br /&gt;
Also hier klicken um ausbaufähige Artikel zu finden:&lt;br /&gt;
* [[:Kategorie:Artikelausbau]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar Artikel wo der Hinweis noch nicht drin steht:&lt;br /&gt;
&lt;br /&gt;
* [[GNU Assembler|AVR Assembler (GNU) Einführung]]:&lt;br /&gt;
* [[Zahnrad]]&lt;br /&gt;
* [[Flipflop]]&lt;br /&gt;
* [[C-Tutorial]] &lt;br /&gt;
* [[Navigation]]&lt;br /&gt;
* [[Transistor]] (noch ein paar Bilder und vielleicht Grundschaltungen mit Beschreibung wären toll&lt;br /&gt;
* [[Avr-gcc|Dokumentation zu avr-gcc]]&lt;br /&gt;
* [[Arm]] Microcontroller&lt;br /&gt;
* [[GPS]] - Aufbau und Anwendung&lt;br /&gt;
* [[SPI]] - Vielleicht noch Beispiele&lt;br /&gt;
* [[Portexpander am AVR]] könnte nen BASCOM-Teil vertragen&lt;br /&gt;
* [[Manchester- Codierung]] - noch ein Programmbeispiel wäre toll&lt;br /&gt;
* [[JTAG]]&lt;br /&gt;
&lt;br /&gt;
== Bereits erfüllte Wünsche ==&lt;br /&gt;
* stellenanzeigen-forum -&amp;gt;Gibt es bereits hier http://www.roboternetz.de/phpBB2/viewforum.php?f=29&lt;br /&gt;
* Filter (Hardware/Software) -&amp;gt; Wurde hier angelegt [[Filter (Elektronik)]]&lt;br /&gt;
* [[Roboterwettbewerbe]]&lt;br /&gt;
* Motortreiber (Einsteigerguide) -&amp;gt; [[Getriebemotoren Ansteuerung]]&lt;br /&gt;
* Kondensator (Grundlagen) -&amp;gt; [[Kondensator]]&lt;br /&gt;
* Quarz-Bausteine -&amp;gt; [[Schwingquarz]] oder [[Quarzoszillator]]&lt;br /&gt;
* [[Roboter-Filme]]&lt;br /&gt;
* Kurzschlußsicherheit, Überspannungsschutz und Verpolungsschutz in [[Schutzschaltungen]]&lt;br /&gt;
* Schnittstellen Übersicht (Es sollten alle gängigen Schnittstellen mit Vorteilen, Nachteilen etc. aufgelistet werden, damit man für jede zu bewältigende Aufgabe die am besten geeignete Schnittstelle wählen kann) -&amp;gt; siehe unter [[RS232]] oder [[RS485]] oder [[USB]], Bussysteme unter [[I2C]] oder [[TWI]] oder [[CAN]] &amp;lt;- was fehlt noch?&lt;br /&gt;
* [[CNY70]] als Liniensensor (analoge / digitale Auswertung)&lt;br /&gt;
* PIC18F... Einführung siehe unter http://www.rn-wissen.de/index.php/PIC_Assembler#High-End &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:RN-Wissen]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=18841</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=18841"/>
				<updated>2012-01-06T21:14:14Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Programmablaufdiagramm (PAD) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste Programm|Das erste Programm]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich.&lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende realisiert. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer unterbrochen und nächster Tast gestartet. Dafür mus immer nach Beenden der ISR unbedingt ins HP gesprungen werden und die Adresse vom PC, wo der Task unterbrochen wurde auf dem Stapel gespeichert werden. Wenn die Zeit für unterbrochener Task wieder kommt, wird er ab unterbrochener Stelle wieder in ihn zustehender Zeit ausgeführt, wieder unterbrochen u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=17517</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=17517"/>
				<updated>2011-07-04T21:28:45Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Das erste... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich.&lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende realisiert. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer unterbrochen und nächster Tast gestartet. Dafür mus immer nach Beenden der ISR unbedingt ins HP gesprungen werden und die Adresse vom PC, wo der Task unterbrochen wurde auf dem Stapel gespeichert werden. Wenn die Zeit für unterbrochener Task wieder kommt, wird er ab unterbrochener Stelle wieder in ihn zustehender Zeit ausgeführt, wieder unterbrochen u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste Programm ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Beispiel_Drehzahlmessung_mit_Drehgeber&amp;diff=17474</id>
		<title>Beispiel Drehzahlmessung mit Drehgeber</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Beispiel_Drehzahlmessung_mit_Drehgeber&amp;diff=17474"/>
				<updated>2011-06-07T16:26:43Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Messen der Drehzahl nach jedem Impuls */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Sensoren]] &lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Motoren]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ermitteln der Drehzahl und Wegstrecke in Abhängigkeit einer Winkeländerung oder Impulsfolge in einer Abgelaufenen Zeit&lt;br /&gt;
&lt;br /&gt;
* Messen der Drehzahl nach jedem Impuls, also in Abhängigkeit einer Winkeländerung.&lt;br /&gt;
* Messen der Drehzahl durch Zählen der Impulse nach Ablauf einer bestimmten Zeit. &lt;br /&gt;
* Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln&lt;br /&gt;
{{Ausbauwunsch|Mehr Grundlagen und vor allem mal praktische Programmbeispiele / Algorithmen etc.}}&lt;br /&gt;
= Messen der Drehzahl nach jedem Impuls =&lt;br /&gt;
&lt;br /&gt;
Dieser Teil beschäftigt sich vor allem mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und [[Gabellichtschranke]] berechnet über die Periodendauer ohne Drehrichtungserkennung.&lt;br /&gt;
[[Bild:GP1S23 Testaufbau.JPG|thumb| Testaufbau mit einer 32er Lochscheibe ]]&lt;br /&gt;
[[Bild:183015_LB_00_FB.EPS_250.jpg|thumb|GP1S23 Gabellichtschranke Bild: Conrad Electronic ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist Impulse direkt an einer Bürste eines Motors zu zählen. Siehe dazu: http://www.roboternetz.de/community/...einem-DC-Motor .&lt;br /&gt;
&lt;br /&gt;
Die [http://de.wikipedia.org/wiki/Winkelgeschwindigkeit Winkelgeschwindigkeit] ist die Winkeländerung pro Zeiteinheit. Mit der Lichtschranke und den geometrischen Daten der Lochscheibe kann man nun relativ einfach die Zeit für eine bestimmte Winkeländerung messen. &lt;br /&gt;
Die Lochscheibe gibt uns die Winkeländerung bei einer Periode vor, bei einer 32er Lochscheibe wären das 11,25° pro Periode , wie in den Bildern vom Oszilloskop zu sehen ändert sich natürlich bei Änderung der Drehzahl die Periodendauer, die Winkeländerung pro Periode ist aber konstant da diese durch die Lochscheibe vor gegeben ist. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Bild:GP1S23_signal_langsam.png|Signal der Lichtschranke bei langsamer Drehzahl &lt;br /&gt;
Bild:GP1S23_signal_schnell.PNG |Signal der Lichtschranke bei schneller Drehzahl &lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um die Periodendauer zu messen verwende ich den ICP1 (Input Capture Pin) eines Atmega8 der bei steigender Flanke den Timer1 ausliest und in das ICR1 Register schreibt. Läuft der Mikrocontroller auf 8Mhz und wir stellen den Vorteiler des Timers auf 8 so bekommen wir die Periodendauer in µs als Wert.&lt;br /&gt;
&lt;br /&gt;
== Auslegen der Lochscheibe ==&lt;br /&gt;
&lt;br /&gt;
In den meisten Fällen definieren der mechanische Aufbau den Durchmesser der Lochscheibe und die Drehzahl die Teilung (Anzahl der Löcher). Der µContoller und die Gabellichtschranke müssen die Impulse auch erfassen und verarbeiten können. Wenn man das Drehzahlband abschätzen kann ist es hilfreich, sich schon Gedanken um die Programmierung zu machen, denn bei hohen Drehzahlen springt der µC jedes mal in die Interrupt Service Routine rein, sofern man es so programmiert wie im Beispiel. Bei hohen Drehzahlen sollte die Teilung somit gröber, bei niedriger Drehzahl die Teilung feiner sein. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Drehscheibe20mm.png|400px|thumb|left|Lochscheibe abgerollt mit idealisiertem Signal ]]&lt;br /&gt;
&lt;br /&gt;
== Berechnungen ==&lt;br /&gt;
&lt;br /&gt;
Hier folgt nun die Berechnung über die Periodendauer, beachten sollte man das im [http://de.wikipedia.org/wiki/Bogenma%C3%9F Bogenmaß] gerechnet wird, ein Winkel mit dem Bogenmaß 1 rad hat ein Gradmaß von ca. 57,3°. 11.25° sind also ca. 0,196 rad, das führt später natürlich zu unschönen Rechenoperationen im µC, Stichwort [http://www.mikrocontroller.net/articles/Festkommaarithmetik Festkommaarithmetik]. &lt;br /&gt;
&lt;br /&gt;
Nach dem Umstellen kommt man aber auf eine recht handliche Formel &amp;lt;math&amp;gt;n = \frac{\varphi }{dt \cdot 360}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist auch eine Überlegung wert, ob man die Drehzahl nicht umrechnet sondern mit der Periodendauer arbeitet. Das ist zwar nicht so geläufig aber das stört den µController nicht. Mit einem Kalkulationsprogramm kann man die Umrechnung von Periodendauer in Drehzahl auch extern vornehmen. &lt;br /&gt;
&lt;br /&gt;
Man sollte sich auch klar machen, das zumindest ein 8-Bit Prozessor am besten mit '''Ganzzahlen''' zwischen 0 und 255 oder 0 und 65535 zurechtkommt. Für die Teilung der Lochscheibe bieten sich deshalb Werte wie 90, 72, 45, 36, 30, 24, 20, 18, 15, 12, 10 und 8 an. Verwendet man an Stelle der dargestellten 32er Lochscheibe eine 30er oder 36er Scheibe, kann man zumindest mit ganzzahligen Gradzahlen rechnen. &amp;quot;Krumme Werte&amp;quot; wie [http://de.wikipedia.org/wiki/Kreiszahl Pi = 3,1415...], [http://de.wikipedia.org/wiki/Radiant_%28Einheit%29 Radiant = 57,29577...°] usw. sollten eine seltene Ausnahme in der Programmierung sein.&lt;br /&gt;
&lt;br /&gt;
= Messen der Drehzahl durch zählen der Impulse =&lt;br /&gt;
&lt;br /&gt;
Dieser Teil beschäftigt sich mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und [[Gabellichtschranke]] berechnet über die die Anzahl der Impulse in einer gewissen Zeit.&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Berechnung==&lt;br /&gt;
&lt;br /&gt;
= Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln =&lt;br /&gt;
Dieser Teil beschäftigt sich mit der Optischen Drehzahl- und Geschwindigkeitsmessung sowie der Erfassung von Drehrichtung und zurückgelegter Position mit Hilfe einer Lochscheibe und 2 Gabellichtschranken. Hierfür werden Quadratursignale in definierten Zeitabständen ausgewertet.&lt;br /&gt;
 &lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Für kontrollierte Bewegungen ist es mitunter wichtig, auch die Drehrichtung/Richtungswechsel und Position auszuwerten. Eine Lochscheibe mit einer Gabellichtschranke liefert lediglich Rechteckimpulse, egal wie rum sich die Lochscheibe bewegt. Bringt man eine zweite Gabellichtschranke an der gleichen Lochscheibe leicht versetzt an, bekommt man auch die Drehrichtung mit. Diese Methode ist altbekannt, simpel und leicht nachzubauen. Wenn man die Drehrichtung kennt, ist auch die Position kein Problem mehr. Ausgehend von einer Kalibrierposition können bei Vorwärtsbewegung Inkremente hochgezählt oder bei Rückwärtsbewegung runtergezählt werden. &lt;br /&gt;
&lt;br /&gt;
Interessierte nehmen dazu mal eine PC-Maus mit Kugelantrieb zur Hand. Darin findet man zwei kleine Lochscheiben, die für die X- und Y-Richtung die Impulse erzeugen. Durch spezielle Gabellichtschranken mit 2 phasenversetzten Ausgängen wird auch die Drehrichtung erkannt. &lt;br /&gt;
&lt;br /&gt;
Das selbe Prinzip ist in linearer Form auch in PC-Druckern zu finden: Entlang des Wagenrücklaufes ist ein transparentes Kunsstoffband gespannt, auf dem winzig kleine Streifenmuster aufgebracht sind. Diese werden von einer Gabellichtschranke mit 2 Ausgängen erkannt und so die Wagenposition gesteuert.&lt;br /&gt;
&lt;br /&gt;
Aber es geht natürlich noch einfacher...&lt;br /&gt;
&lt;br /&gt;
== Zwei Lichtschranken liefern vier Informationen ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:vorwaerts_.jpg|thumb|Zustandsfolge bei Vorwärtsbewegung]]&lt;br /&gt;
[[Bild:rueckwaerts_.jpg|thumb|Zustandsfolge bei Rückwärtsbewegung]]&lt;br /&gt;
[[Bild:2LSZustand.jpg|thumb|2 Lichtschranken (LSA und LSB) liefern phasenversetzte Rechtecksignale. In Vorwärts- und Rückwärtsrichtung ergeben sich unterschiedliche Zustandsfolgen]]&lt;br /&gt;
&lt;br /&gt;
Man nimmt 2 normale Gabellichtschranken und bringt sie so an, das sie im 1,5 fachen Lochabstand die Lochscheibe durchleuchten. Wenn sich Lichtschranke A in der Mitte des Lichtstreifens befindet, ist Lichtschranke B an der Grenze des Schattenstreifens. Nebenstehende Skizzen zeigen die möglichen Zustände beider Lichtschranken bei Vorwärts- und Rückwärtsbewgung der Lochscheibe. Wichtig ist hierbei, das die Lochscheibe in gleich breite Licht- und Schattensegmente eingeteilt ist und die Lichtschranke(n) einen möglichst haarfeinen Lichtstrahl besitzt. Die Signale der Fototransistoren sollten verstärkt und gegebenenfalls mit TTL-Bausteinen zu korrekten High- und Low-Pegeln aufbereitet werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es ergeben sich nun folgende Kombinationen:&lt;br /&gt;
&lt;br /&gt;
* Zustand 1:    LSA =   hell und LSB =   hell&lt;br /&gt;
* Zustand 2:    LSA =   hell und LSB = dunkel&lt;br /&gt;
* Zustand 3:    LSA = dunkel und LSB = dunkel&lt;br /&gt;
* Zustand 4:    LSA = dunkel und LSB =   hell&lt;br /&gt;
&lt;br /&gt;
Dreht man die Lochscheibe weiter, wiederholt sich der Vorgang. Die Zustandsfolge ist 1 &amp;gt; 2 &amp;gt; 3 &amp;gt; 4 &amp;gt; 1 &amp;gt; 2 &amp;gt; 3 &amp;gt; 4 &amp;gt;  usw.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei entgegengesetzter Drehrichtung ändert sich diese Reihenfolge. Betrachtet man wieder vom Zustand 1 ausgehend die Gegenrichtung, ergeben sich nun diese Kombinationen:&lt;br /&gt;
&lt;br /&gt;
* Zustand 1:    LSA =   hell und LSB =   hell&lt;br /&gt;
* Zustand 4:    LSA = dunkel und LSB =   hell&lt;br /&gt;
* Zustand 3:    LSA = dunkel und LSB = dunkel&lt;br /&gt;
* Zustand 2:    LSA =   hell und LSB = dunkel&lt;br /&gt;
&lt;br /&gt;
Die Zustandsfolge in Gegenrichtung lautet dann: 1 &amp;lt; 4 &amp;lt; 3 &amp;lt; 2 &amp;lt; 1 &amp;lt; 4 &amp;lt; 3 &amp;lt; 2 &amp;lt;  usw.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit diesem Wissen ist es nun ein Kinderspiel, auch die Änderung der Drehrichtung festzustellen. Dazu muss der letzte Zustand in einer Variable gespeichert und mit dem neu erkannten Zustand verglichen werden. Folgt nach Zustand 1 der Zustand 2, so ist es eine Vorwärtsbewegung. Folgt dem Zustand 1 der Zustand 4, so ist es eine Rückwärtsbewegung. Gleiches Prinzip gilt auch für die restlichen Zustände 2, 3 und 4.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Positionsüberwachung ==&lt;br /&gt;
&lt;br /&gt;
Von jedem der 4 Zustände gibt es also zwei zu unterscheidende Fälle: Vorwärts und Rückwärts. Insgesamt müssen demzufolge 8 Bedingungen zyklisch abgetastet und ein Positionszähler entsprechend inkrementiert oder dekrementiert werden und schon hat man eine exakte Streckeninformation. In Worte gefasst ergibt sich folgende Logik:&lt;br /&gt;
&lt;br /&gt;
Ausgangszustand: Beide Lichtschranken sind aus (A=0 UND B=0) und Zustand =1&lt;br /&gt;
&lt;br /&gt;
* WENN (Zustand=1 UND A=0 UND B=1) DANN: Setze Zustand=2, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=1 UND A=1 UND B=0) DANN: Setze Zustand=4, Position dekrementieren, Rück&lt;br /&gt;
* WENN (Zustand=2 UND A=1 UND B=1) DANN: Setze Zustand=3, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=2 UND A=0 UND B=0) DANN: Setze Zustand=1, Position dekrementieren, Rück&lt;br /&gt;
* WENN (Zustand=3 UND A=1 UND B=0) DANN: Setze Zustand=4, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=3 UND A=0 UND B=1) DANN: Setze Zustand=2, Position dekrementieren, Rück&lt;br /&gt;
* WENN (Zustand=4 UND A=0 UND B=0) DANN: Setze Zustand=1, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=4 UND A=1 UND B=1) DANN: Setze Zustand=3, Position dekrementieren, Rück&lt;br /&gt;
[[Bild:Lochscheibe8.jpg|thumb|Lochscheibe 8 ]]&lt;br /&gt;
[[Bild:Lochscheibe10.jpg|thumb|Lochscheibe 10 ]]&lt;br /&gt;
[[Bild:Lochscheibe12.jpg|thumb|Lochscheibe 12 ]]&lt;br /&gt;
[[Bild:Lochscheibe15.jpg|thumb|Lochscheibe 15 ]]&lt;br /&gt;
[[Bild:Lochscheibe18.jpg|thumb|Lochscheibe 18 ]]&lt;br /&gt;
[[Bild:Lochscheibe20.jpg|thumb|Lochscheibe 20 ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Prüfung muss ständig wiederholt werden, damit alle Pegelwechsel der beiden Lichtschranken erfasst werden. Nur so ist es möglich, die exakte Position zu verfolgen. Dafür bieten sich 2 Möglichkeiten: Entweder die Prüfung wird im Hauptprogramm ständig durchlaufen (Polling) oder ein Timer-Interrupt tastet regelmäßig die Lichtschranken ab. Hier soll nur die zweite, also Interruptvariante betrachtet werden, weil sie mehr Vorteile bringt. Weiter unten im Artikel ist dazu ein Beispiel in Sprache C zu finden. &lt;br /&gt;
&lt;br /&gt;
Zuvor muss aber eine sinnvolle Auslegung von Lochscheibe, Drehzahl und Positionsbereich gefunden und in Einklang mit den Ressourcen des verwendeten µControlles gebracht werden. Dazu folgende Betrachtungen:&lt;br /&gt;
&lt;br /&gt;
Wenn 2 phasenversetzte  Lichtschranken je Hell-/ Dunkelzyklus bereits 4 Positionen liefern, benötigt die Lochscheibe nur halb so viel &amp;quot;Löcher&amp;quot; wie eine Lochscheibe bei Verwendung nur einer Lichtschranke. Eine 15er Lochscheibe liefert demzufolge 15x4 = 60 Positionen auf 360°, das sind 6° je erfasster Position. Entscheidend ist, an welchem Antriebsteil die Lochscheibe montiert ist und mit welcher Untersetzung zwischen Motor und Abtriebswelle(Rad) gearbeitet wird. Ist die Lochscheibe an der Motorwelle angebracht, würde bei einer angenommenen Untersetzung von 10:1 eine erfasste Position nur 0,6° an der Abtriebswelle ausmachen. &lt;br /&gt;
&lt;br /&gt;
Man muss sich klar machen, welche '''Positioniergenauigkeit''' nötig ist. Dabei gilt: Auslegung so genau wie nötig, nicht wie möglich. Weiter muss geklärt werden, wo man die Lochscheibe sinnvoll anbringt. Sie darf im Betrieb weder verschmutzt oder beschädigt werden. Fahrmodelle ziehen Staub, Haare etc. gern an, gut beraten ist man mit einer '''verkapselten Optomechanik'''. Ein weiterer Faktor ist die '''Drehzahl''' (im Leerlauf am höchsten) des Motors, weil diese die Frequenz der abzutastenden Signale beeinflusst. Zwischen Drehzahl n [U/min], Frequenz f [Hz] und Teilung T besteht folgender Zusammenhang:&lt;br /&gt;
&lt;br /&gt;
'''f = n * T / 60 s'''&lt;br /&gt;
&lt;br /&gt;
Beispiel: Ein Motor dreht im Leerlauf mit 2370 U/min und hat eine Lochscheibe mit Teilung = 12 an der Motorwelle. Die Frequenz der abzutastenden Signale einer Lichtschranke soll ermittelt werden. (oben im Osszillogramm dargestellt)&lt;br /&gt;
&lt;br /&gt;
'''f = 2370 * 12 / 60 s'''&lt;br /&gt;
&lt;br /&gt;
'''f = 474 Hz'''&lt;br /&gt;
&lt;br /&gt;
Eine Lichtschranke liefert also ein Rechtecksignal mit f = 474 Hz. Jetzt muss noch das Signal der zweiten Lichtschranke um 90° versetzt darübergelegt werden. Bei idealen Pegeln sind in einer Periode 4 Schaltzustände abzutasten, also muss die Abtastfrequenz mindestens 4-fach über der Grundfrequenz liegen. Da es in der Praxis aber keine idealen Pegel gibt, muss die Abtastfrequenz noch höher ausgelegt werden. Betrachten wir noch mal das Osszillogrammm weiter oben:&lt;br /&gt;
&lt;br /&gt;
Es fällt auf, das die Zeiten nicht exakt gleich sind, die Zustandszeiten 1 und 3 sind etwas länger als 2 und 4. Das liegt an der Einstellung des Abstandes beider Lichtschranken zueinander, die Phasenlage ist hier nicht genau 90°. Außerdem sind Lochscheibe und Lichtschranken mit kleinen Unregelmäßikeiten, Streuungen, Anstiegs- und Abfallzeiten behaftet, so dass es in einer Periode auch Zeiten gibt, die nicht eindeutig einem der 4 genannten Zustände entsprechen. Für eine sichere Abtastung ist deshalb von der kürzesten (= ungünstigsten) Schaltzeit auszugehen, hier sind es ca. 0,4 Millisekunden, das entspricht 2,5 kHz. Jeder Zustand sollte vom µController sicherheitshalber schon 3 bis 4 mal abgetastet werden, so das wir für das Beispiel mindestens ca. 10 kHz Abtastfrequenz einplanen müssen. Als Orientierungshilfe gilt:&lt;br /&gt;
&lt;br /&gt;
'''Abtastfrequenz &amp;gt;= 20 * Frequenz Lichtschranke'''&lt;br /&gt;
&lt;br /&gt;
Entsprechend der gewünschten Positioniergenauigkeit und Drehzahl kann nun die Teilung der Lochscheibe so gewählt werden, das die Lichtschrankensignale vom µController abgetastet werden können. Da Kaufteile aus dem Industriebereich oft eine recht hohe Teilung vorgeben, ist es manchmal besser, mit kleineren Teilungen anzufangen. Rechts sind Vorlagen, die man sich auf Folien ausdrucken kann.(Nähere Beschreibung im Praxis-Teil)&lt;br /&gt;
&lt;br /&gt;
Die Abtastung muss sicher sein, auch wenn das Hauptprogramm gerade mit anderen Dingen als der Lochscheibenauswertung beschäftigt ist. Man kann zwar die Lochscheibe vom Hauptprogramm durchaus mit abfragen lassen, aber dann sollten keine anderen zeitraubenden Prozeduren darin enthalten sein. Ist nur ein Zustandswechsel übersehen und ausgelassen wurden, geht es erst an der nachfolgenden gleichen Hell-/Dunkel-Kombination weiter und der Contoller verzählt sich um 4 Inkremente! Deshalb sollte die TimerInterrupt-Variante vorgezogen oder die Abtastung in einen separaten µController ausgelagert werden.&lt;br /&gt;
&lt;br /&gt;
Der Positionsbereich muss schließlich auch in einer Variablen dargestellt werden. Im Beispiel mit Teilung =12 wird der Positionzähler bei einer Motorumdrehung um 48 Inkremente hochgezählt. Bei 2370 U/min wäre eine 16Bit-Variable nach ca. 34 Sekunden übergelaufen. Demzufolge ist auch das Speichervolumen der Positionsvariablen dem tatsächlichen Fahrbereich anzupassen. Man kann auch Ober-/ Untergrenzen definieren, die bei Erreichen den Antrieb anhalten. Somit wird ein mechanisches Überfahren von Endlagen oder ein logisches Überlaufen von Variablen verhindert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Zusammenfassung:'''&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|&lt;br /&gt;
# Welche Positionsgenauigkeit brauch ich?&lt;br /&gt;
# Sind Lochscheibe und Optik vor Störeinflüssen geschützt?&lt;br /&gt;
# Welche maximale Drehzahl muss noch sicher abgetastet werden?&lt;br /&gt;
# Frequenz Lichtschranke anpassen: Hohe Drehzahl mit kleiner Teilung / geringe Drehzahl mit großer Teilung&lt;br /&gt;
# Phasenlage richtig eingestellt? Optimal sind 90°&lt;br /&gt;
# Positionsvariable mit genügend Speichervolumen?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Kalibrierung ==&lt;br /&gt;
&lt;br /&gt;
Im einfachsten Fall fährt man seinem Antrieb auf eine Referenzmarke (Nonius, Paßstift o.ä.) und setzt dort den Positionszähler zurück. &lt;br /&gt;
&lt;br /&gt;
Wer es noch genauer will, muß auch noch die Lochscheibe in eine definierte Ausgangsstellung bringen. Dazu kann man die Lichtschrankensignale mit 2 LEDs optisch anzeigen. In der Kalibrierstellung müssen dann der Antrieb auf der Refernzmarke stehen und beide LEDs leuchten. Als Referenzmarke kann natürlich auch eine zusätzliche Lichtschranke dienen, die eine kleine Bohrung am Antrieb erkennt. Wichtig ist, dass die Referenzmarke nur einmal und eindeutig am Antrieb angebracht ist.&lt;br /&gt;
&lt;br /&gt;
== Geschwindigkeit und Beschleunigung ==&lt;br /&gt;
&lt;br /&gt;
Geschwindigkeit wird meist in [m/s], [km/h] oder [mph] ausgedrückt, also der Wegstrecke je Zeiteinheit. Im µController interessieren uns diese Einheiten erst mal nicht, hier werden Inkremente je Zeiteinheit gezählt. Die Zeitintervalle, in denen die Inkremente ausgewertet werden, liefert wieder ein TimerInterrupt. Dieser ist mit deutlich längeren Zyklen auszulegen, damit auch genügend Inkremente je Zyklus gezählt werden können. Im Code-Beispiel unten werden bei 16Mhz CPU-Takt die Vorteiler 1 und 1024 für die TimerInterrupt´s verwendet: Timer 0 mit Prescaler =1024 für die Geschwindigkeitsberechnung mit ca. 61 Hz und Timer 2 mit Prescaler =1 für die Abtastung der Lichtschranken mit 62,5 kHz. Die Geschwindigkeitsmessung wurde mit 12er, 15er und 18er Teilung getestet. In der ISR des Timer_0 Overflow wird die Differenz aus aktueller Position und der Position des vergangenen Zyklus gebildet. Da diese Wegdifferenz in definierten Zeitabständen ermittelt wird, hat man hier bereits die Geschwindigkeit in n Inkremente je 0,01638 Sekunden. Mit dieser etwas abstrakten Geschwindigkeitseinheit wird im Hauptprogramm der Motor gesteuert.&lt;br /&gt;
&lt;br /&gt;
Das gleiche Verfahren ist auch für die Beschleunigung anwendbar. Die Beschleunigung ist die Geschwindigkeitsänderung je Zeiteinheit. In der ISR des Timer_0 Overflow kann die Differenz aus aktueller Geschwindigkeit und der Geschwindigkeit des vergangenen Zyklus gebildet werden, um so die Beschleunigung zu erhalten. Die Einheit ist wieder etwas ungewohnt: Inkremente je 0,01638 Sekunden in 0,01638 Sekunden, also Inkremente/Quadratsekunden. Voraussetzung für eine vernünftige Beschleunigungsermittlung ist, das eine genügend hohe Auflösung der Geschwindigkeit vorliegt(=hohe Teilung der Lochscheibe). Ansonsten sind die ermittelten Werte zu klein und liegen, je nach Trägheit des Motors, fast immer bei 0, 1, 2 oder maximal 3.&lt;br /&gt;
&lt;br /&gt;
Vorteil der Differenzmethode ist, man kann die Geschwindigkeit in einer 8Bit-Variable mit Vorzeichen ausdrücken. Die Werte des Beispieles lagen je nach Teilung zwischen -50 und +50 und sind für die Motorsteuerung ausreichend. Bessere Auflösung erfordert höhere Teilung, höhere Abtastrate, höhere CPU-Frequenz.&lt;br /&gt;
&lt;br /&gt;
== Praxis==&lt;br /&gt;
&lt;br /&gt;
=== Herstellung der Lochscheibe ===&lt;br /&gt;
Für eigene Projekte ist es mitunter schwer, Lochscheiben in passender Größe und Teilung zu finden. Oft müssen dann Kompromisse in der Drehzahlsteuerung oder Positionierung gemacht werden, weil die vielleicht günstigere Teilung nicht zu beschaffen ist. &lt;br /&gt;
&lt;br /&gt;
Hier wird deshalb ein Selbstbau von preiswerten Lochscheiben vorgestellt: Man trägt in einer Excel-Tabelle z.B. 18 mal die Zahl 20 ein und markiert diesen Zellbereich. Anschließend erstellt man mit dem Diagramm-Assistent ein Ring-Diagramm. Darin muss man nun jeden Datenpunkt einzeln formatieren und abwechslend die Farbe schwarz und weiß zuordnen. Markiert man die komplette Datenreihe, kann man unter 'Formatieren'&amp;gt;'Optionen' auch die Innenringgröße einstellen. Dieses Ring-Diagramm kann nun beliebig kopiert und vergößert oder verkleinert werden, auch die Datenreihe kann auf z.B. 24x15 oder 30x12 angepasst werden. So lassen sich auf einer A4-Seite einige Dutzend Lochscheiben in allen Größen und Teilungen herstellen. Das fertige Arbeitsblatt muss nun noch mit geeigneter Tinte auf Folie ausgedruckt werden. Den Drucker muss man möglichst auf satte Farbe und kräftgen Kontrast einstellen. Zum Schluß wird die ausgedruckte Folie mit A4- Laminierfolie verstärkt, wer kein Laminiergerät hat, geht in einen Copy-Shop o.ä. &lt;br /&gt;
&lt;br /&gt;
Die so gewonnenen Lochscheiben werden nun ausgeschnitten und bei Bedarf mit einem Heißluftgerät noch etwas &amp;quot;nachgebacken&amp;quot;, bevor sie im eigenen Projekt mit Kraftkleber auf ein kleines Rad aufgeklebt werden. Hierbei auf gute Zentrierung achten, damit die Lochscheibe möglichst rund läuft. Sekundenkleber ist deshalb ungeeignet, weil kaum Zeit für Korrektur und Einstellung bleibt.&lt;br /&gt;
&lt;br /&gt;
=== Anpassen der Lichtschranke ===&lt;br /&gt;
&lt;br /&gt;
Baustelle:&lt;br /&gt;
&lt;br /&gt;
Fotos, Anregungen zum Nachbau, Beschaffung, Erfahrungen&lt;br /&gt;
&lt;br /&gt;
weiterführende Informationen:&lt;br /&gt;
[http://de.wikipedia.org/wiki/Inkrementalgeber Inkrementalgeber]&lt;br /&gt;
&lt;br /&gt;
=== Quelcode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//Deklaration global&lt;br /&gt;
volatile uint8_t Zust_Li;            //Zustandsmerker Position linker Motor&lt;br /&gt;
volatile uint16_t Li_Inkr;           //aktuelle Position linker Motor&lt;br /&gt;
volatile uint16_t old_Li_Inkr;       //Position im vorangegangenen Takt&lt;br /&gt;
volatile int8_t Speed_Li_Ist;        //Wegänderung je Takt, in ISR Timer 0&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
// Interrupt-Service-Routine  Timer_0 Overflow&lt;br /&gt;
SIGNAL (SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
  // ISR-Code  61,035 Pro Sekunde&lt;br /&gt;
  Timeout++;&lt;br /&gt;
  Speed_Li_Ist = Li_Inkr - old_Li_Inkr;&lt;br /&gt;
  old_Li_Inkr = Li_Inkr;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Interrupt-Service-Routine  Timer_2 Overflow&lt;br /&gt;
SIGNAL (SIG_OVERFLOW2)&lt;br /&gt;
{&lt;br /&gt;
  // ISR-Code  62.5 kHz&lt;br /&gt;
  // 4 Zustaende durch jeweils 1 Bit repräsentiert (1,2,4,8)&lt;br /&gt;
  // Lichtschranke A liegt an Port A.0&lt;br /&gt;
  // Lichtschranke B liegt an Port A.1&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 1) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 2;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 1) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 8;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 2) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 4;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 2) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 1;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 4) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 8;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 4) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 2;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 8) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 1;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 8) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 4;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
//Init&lt;br /&gt;
TCCR2 |= (1&amp;lt;&amp;lt;CS20);                  //Prescaler = 1 (16MHz/1 = 16000000) -&amp;gt;&lt;br /&gt;
                                     //16000000/256 -&amp;gt; 62500 Interrupts je Sekunde&lt;br /&gt;
&lt;br /&gt;
TCCR0 |= (1&amp;lt;&amp;lt;CS02)|(1&amp;lt;&amp;lt;CS00);        //Prescaler = 1024  (16000000 / 1024 = 15625) -&amp;gt;&lt;br /&gt;
                                     //15625/256 = 61,035  -&amp;gt; 61 Interrupts je Sekunde&lt;br /&gt;
&lt;br /&gt;
TIMSK |= (1&amp;lt;&amp;lt;TOIE0)|(1&amp;lt;&amp;lt;TOIE2);      //Timer Overflow Interrupt Enablae für Timer 0 und 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Li_Inkr = 32000;Zust_Li = 1;         // Kalibrierstellung bei 32000&lt;br /&gt;
sei();                               // Interrupts aktivieren&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  while(1)&lt;br /&gt;
  {&lt;br /&gt;
&lt;br /&gt;
  // hier kann Position und Geschwindigkeit ausgewertet werden&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
= Vor und Nachteile der Messmethoden=&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Beispiel_Drehzahlmessung_mit_Drehgeber&amp;diff=17473</id>
		<title>Beispiel Drehzahlmessung mit Drehgeber</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Beispiel_Drehzahlmessung_mit_Drehgeber&amp;diff=17473"/>
				<updated>2011-06-07T16:26:09Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Sensoren]] &lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Motoren]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ermitteln der Drehzahl und Wegstrecke in Abhängigkeit einer Winkeländerung oder Impulsfolge in einer Abgelaufenen Zeit&lt;br /&gt;
&lt;br /&gt;
* Messen der Drehzahl nach jedem Impuls, also in Abhängigkeit einer Winkeländerung.&lt;br /&gt;
* Messen der Drehzahl durch Zählen der Impulse nach Ablauf einer bestimmten Zeit. &lt;br /&gt;
* Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln&lt;br /&gt;
{{Ausbauwunsch|Mehr Grundlagen und vor allem mal praktische Programmbeispiele / Algorithmen etc.}}&lt;br /&gt;
= Messen der Drehzahl nach jedem Impuls =&lt;br /&gt;
&lt;br /&gt;
Dieser Teil beschäftigt sich vr allem mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und [[Gabellichtschranke]] berechnet über die Periodendauer ohne Drehrichtungserkennung.&lt;br /&gt;
[[Bild:GP1S23 Testaufbau.JPG|thumb| Testaufbau mit einer 32er Lochscheibe ]]&lt;br /&gt;
[[Bild:183015_LB_00_FB.EPS_250.jpg|thumb|GP1S23 Gabellichtschranke Bild: Conrad Electronic ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist Impulse direkt an einer Bürste eines Motors zu zählen. Siehe dazu: http://www.roboternetz.de/community/...einem-DC-Motor .&lt;br /&gt;
&lt;br /&gt;
Die [http://de.wikipedia.org/wiki/Winkelgeschwindigkeit Winkelgeschwindigkeit] ist die Winkeländerung pro Zeiteinheit. Mit der Lichtschranke und den geometrischen Daten der Lochscheibe kann man nun relativ einfach die Zeit für eine bestimmte Winkeländerung messen. &lt;br /&gt;
Die Lochscheibe gibt uns die Winkeländerung bei einer Periode vor, bei einer 32er Lochscheibe wären das 11,25° pro Periode , wie in den Bildern vom Oszilloskop zu sehen ändert sich natürlich bei Änderung der Drehzahl die Periodendauer, die Winkeländerung pro Periode ist aber konstant da diese durch die Lochscheibe vor gegeben ist. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Bild:GP1S23_signal_langsam.png|Signal der Lichtschranke bei langsamer Drehzahl &lt;br /&gt;
Bild:GP1S23_signal_schnell.PNG |Signal der Lichtschranke bei schneller Drehzahl &lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um die Periodendauer zu messen verwende ich den ICP1 (Input Capture Pin) eines Atmega8 der bei steigender Flanke den Timer1 ausliest und in das ICR1 Register schreibt. Läuft der Mikrocontroller auf 8Mhz und wir stellen den Vorteiler des Timers auf 8 so bekommen wir die Periodendauer in µs als Wert.&lt;br /&gt;
&lt;br /&gt;
== Auslegen der Lochscheibe ==&lt;br /&gt;
&lt;br /&gt;
In den meisten Fällen definieren der mechanische Aufbau den Durchmesser der Lochscheibe und die Drehzahl die Teilung (Anzahl der Löcher). Der µContoller und die Gabellichtschranke müssen die Impulse auch erfassen und verarbeiten können. Wenn man das Drehzahlband abschätzen kann ist es hilfreich, sich schon Gedanken um die Programmierung zu machen, denn bei hohen Drehzahlen springt der µC jedes mal in die Interrupt Service Routine rein, sofern man es so programmiert wie im Beispiel. Bei hohen Drehzahlen sollte die Teilung somit gröber, bei niedriger Drehzahl die Teilung feiner sein. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Drehscheibe20mm.png|400px|thumb|left|Lochscheibe abgerollt mit idealisiertem Signal ]]&lt;br /&gt;
&lt;br /&gt;
== Berechnungen ==&lt;br /&gt;
&lt;br /&gt;
Hier folgt nun die Berechnung über die Periodendauer, beachten sollte man das im [http://de.wikipedia.org/wiki/Bogenma%C3%9F Bogenmaß] gerechnet wird, ein Winkel mit dem Bogenmaß 1 rad hat ein Gradmaß von ca. 57,3°. 11.25° sind also ca. 0,196 rad, das führt später natürlich zu unschönen Rechenoperationen im µC, Stichwort [http://www.mikrocontroller.net/articles/Festkommaarithmetik Festkommaarithmetik]. &lt;br /&gt;
&lt;br /&gt;
Nach dem Umstellen kommt man aber auf eine recht handliche Formel &amp;lt;math&amp;gt;n = \frac{\varphi }{dt \cdot 360}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist auch eine Überlegung wert, ob man die Drehzahl nicht umrechnet sondern mit der Periodendauer arbeitet. Das ist zwar nicht so geläufig aber das stört den µController nicht. Mit einem Kalkulationsprogramm kann man die Umrechnung von Periodendauer in Drehzahl auch extern vornehmen. &lt;br /&gt;
&lt;br /&gt;
Man sollte sich auch klar machen, das zumindest ein 8-Bit Prozessor am besten mit '''Ganzzahlen''' zwischen 0 und 255 oder 0 und 65535 zurechtkommt. Für die Teilung der Lochscheibe bieten sich deshalb Werte wie 90, 72, 45, 36, 30, 24, 20, 18, 15, 12, 10 und 8 an. Verwendet man an Stelle der dargestellten 32er Lochscheibe eine 30er oder 36er Scheibe, kann man zumindest mit ganzzahligen Gradzahlen rechnen. &amp;quot;Krumme Werte&amp;quot; wie [http://de.wikipedia.org/wiki/Kreiszahl Pi = 3,1415...], [http://de.wikipedia.org/wiki/Radiant_%28Einheit%29 Radiant = 57,29577...°] usw. sollten eine seltene Ausnahme in der Programmierung sein.&lt;br /&gt;
&lt;br /&gt;
= Messen der Drehzahl durch zählen der Impulse =&lt;br /&gt;
&lt;br /&gt;
Dieser Teil beschäftigt sich mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und [[Gabellichtschranke]] berechnet über die die Anzahl der Impulse in einer gewissen Zeit.&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Berechnung==&lt;br /&gt;
&lt;br /&gt;
= Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln =&lt;br /&gt;
Dieser Teil beschäftigt sich mit der Optischen Drehzahl- und Geschwindigkeitsmessung sowie der Erfassung von Drehrichtung und zurückgelegter Position mit Hilfe einer Lochscheibe und 2 Gabellichtschranken. Hierfür werden Quadratursignale in definierten Zeitabständen ausgewertet.&lt;br /&gt;
 &lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Für kontrollierte Bewegungen ist es mitunter wichtig, auch die Drehrichtung/Richtungswechsel und Position auszuwerten. Eine Lochscheibe mit einer Gabellichtschranke liefert lediglich Rechteckimpulse, egal wie rum sich die Lochscheibe bewegt. Bringt man eine zweite Gabellichtschranke an der gleichen Lochscheibe leicht versetzt an, bekommt man auch die Drehrichtung mit. Diese Methode ist altbekannt, simpel und leicht nachzubauen. Wenn man die Drehrichtung kennt, ist auch die Position kein Problem mehr. Ausgehend von einer Kalibrierposition können bei Vorwärtsbewegung Inkremente hochgezählt oder bei Rückwärtsbewegung runtergezählt werden. &lt;br /&gt;
&lt;br /&gt;
Interessierte nehmen dazu mal eine PC-Maus mit Kugelantrieb zur Hand. Darin findet man zwei kleine Lochscheiben, die für die X- und Y-Richtung die Impulse erzeugen. Durch spezielle Gabellichtschranken mit 2 phasenversetzten Ausgängen wird auch die Drehrichtung erkannt. &lt;br /&gt;
&lt;br /&gt;
Das selbe Prinzip ist in linearer Form auch in PC-Druckern zu finden: Entlang des Wagenrücklaufes ist ein transparentes Kunsstoffband gespannt, auf dem winzig kleine Streifenmuster aufgebracht sind. Diese werden von einer Gabellichtschranke mit 2 Ausgängen erkannt und so die Wagenposition gesteuert.&lt;br /&gt;
&lt;br /&gt;
Aber es geht natürlich noch einfacher...&lt;br /&gt;
&lt;br /&gt;
== Zwei Lichtschranken liefern vier Informationen ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:vorwaerts_.jpg|thumb|Zustandsfolge bei Vorwärtsbewegung]]&lt;br /&gt;
[[Bild:rueckwaerts_.jpg|thumb|Zustandsfolge bei Rückwärtsbewegung]]&lt;br /&gt;
[[Bild:2LSZustand.jpg|thumb|2 Lichtschranken (LSA und LSB) liefern phasenversetzte Rechtecksignale. In Vorwärts- und Rückwärtsrichtung ergeben sich unterschiedliche Zustandsfolgen]]&lt;br /&gt;
&lt;br /&gt;
Man nimmt 2 normale Gabellichtschranken und bringt sie so an, das sie im 1,5 fachen Lochabstand die Lochscheibe durchleuchten. Wenn sich Lichtschranke A in der Mitte des Lichtstreifens befindet, ist Lichtschranke B an der Grenze des Schattenstreifens. Nebenstehende Skizzen zeigen die möglichen Zustände beider Lichtschranken bei Vorwärts- und Rückwärtsbewgung der Lochscheibe. Wichtig ist hierbei, das die Lochscheibe in gleich breite Licht- und Schattensegmente eingeteilt ist und die Lichtschranke(n) einen möglichst haarfeinen Lichtstrahl besitzt. Die Signale der Fototransistoren sollten verstärkt und gegebenenfalls mit TTL-Bausteinen zu korrekten High- und Low-Pegeln aufbereitet werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es ergeben sich nun folgende Kombinationen:&lt;br /&gt;
&lt;br /&gt;
* Zustand 1:    LSA =   hell und LSB =   hell&lt;br /&gt;
* Zustand 2:    LSA =   hell und LSB = dunkel&lt;br /&gt;
* Zustand 3:    LSA = dunkel und LSB = dunkel&lt;br /&gt;
* Zustand 4:    LSA = dunkel und LSB =   hell&lt;br /&gt;
&lt;br /&gt;
Dreht man die Lochscheibe weiter, wiederholt sich der Vorgang. Die Zustandsfolge ist 1 &amp;gt; 2 &amp;gt; 3 &amp;gt; 4 &amp;gt; 1 &amp;gt; 2 &amp;gt; 3 &amp;gt; 4 &amp;gt;  usw.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei entgegengesetzter Drehrichtung ändert sich diese Reihenfolge. Betrachtet man wieder vom Zustand 1 ausgehend die Gegenrichtung, ergeben sich nun diese Kombinationen:&lt;br /&gt;
&lt;br /&gt;
* Zustand 1:    LSA =   hell und LSB =   hell&lt;br /&gt;
* Zustand 4:    LSA = dunkel und LSB =   hell&lt;br /&gt;
* Zustand 3:    LSA = dunkel und LSB = dunkel&lt;br /&gt;
* Zustand 2:    LSA =   hell und LSB = dunkel&lt;br /&gt;
&lt;br /&gt;
Die Zustandsfolge in Gegenrichtung lautet dann: 1 &amp;lt; 4 &amp;lt; 3 &amp;lt; 2 &amp;lt; 1 &amp;lt; 4 &amp;lt; 3 &amp;lt; 2 &amp;lt;  usw.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit diesem Wissen ist es nun ein Kinderspiel, auch die Änderung der Drehrichtung festzustellen. Dazu muss der letzte Zustand in einer Variable gespeichert und mit dem neu erkannten Zustand verglichen werden. Folgt nach Zustand 1 der Zustand 2, so ist es eine Vorwärtsbewegung. Folgt dem Zustand 1 der Zustand 4, so ist es eine Rückwärtsbewegung. Gleiches Prinzip gilt auch für die restlichen Zustände 2, 3 und 4.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Positionsüberwachung ==&lt;br /&gt;
&lt;br /&gt;
Von jedem der 4 Zustände gibt es also zwei zu unterscheidende Fälle: Vorwärts und Rückwärts. Insgesamt müssen demzufolge 8 Bedingungen zyklisch abgetastet und ein Positionszähler entsprechend inkrementiert oder dekrementiert werden und schon hat man eine exakte Streckeninformation. In Worte gefasst ergibt sich folgende Logik:&lt;br /&gt;
&lt;br /&gt;
Ausgangszustand: Beide Lichtschranken sind aus (A=0 UND B=0) und Zustand =1&lt;br /&gt;
&lt;br /&gt;
* WENN (Zustand=1 UND A=0 UND B=1) DANN: Setze Zustand=2, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=1 UND A=1 UND B=0) DANN: Setze Zustand=4, Position dekrementieren, Rück&lt;br /&gt;
* WENN (Zustand=2 UND A=1 UND B=1) DANN: Setze Zustand=3, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=2 UND A=0 UND B=0) DANN: Setze Zustand=1, Position dekrementieren, Rück&lt;br /&gt;
* WENN (Zustand=3 UND A=1 UND B=0) DANN: Setze Zustand=4, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=3 UND A=0 UND B=1) DANN: Setze Zustand=2, Position dekrementieren, Rück&lt;br /&gt;
* WENN (Zustand=4 UND A=0 UND B=0) DANN: Setze Zustand=1, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=4 UND A=1 UND B=1) DANN: Setze Zustand=3, Position dekrementieren, Rück&lt;br /&gt;
[[Bild:Lochscheibe8.jpg|thumb|Lochscheibe 8 ]]&lt;br /&gt;
[[Bild:Lochscheibe10.jpg|thumb|Lochscheibe 10 ]]&lt;br /&gt;
[[Bild:Lochscheibe12.jpg|thumb|Lochscheibe 12 ]]&lt;br /&gt;
[[Bild:Lochscheibe15.jpg|thumb|Lochscheibe 15 ]]&lt;br /&gt;
[[Bild:Lochscheibe18.jpg|thumb|Lochscheibe 18 ]]&lt;br /&gt;
[[Bild:Lochscheibe20.jpg|thumb|Lochscheibe 20 ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Prüfung muss ständig wiederholt werden, damit alle Pegelwechsel der beiden Lichtschranken erfasst werden. Nur so ist es möglich, die exakte Position zu verfolgen. Dafür bieten sich 2 Möglichkeiten: Entweder die Prüfung wird im Hauptprogramm ständig durchlaufen (Polling) oder ein Timer-Interrupt tastet regelmäßig die Lichtschranken ab. Hier soll nur die zweite, also Interruptvariante betrachtet werden, weil sie mehr Vorteile bringt. Weiter unten im Artikel ist dazu ein Beispiel in Sprache C zu finden. &lt;br /&gt;
&lt;br /&gt;
Zuvor muss aber eine sinnvolle Auslegung von Lochscheibe, Drehzahl und Positionsbereich gefunden und in Einklang mit den Ressourcen des verwendeten µControlles gebracht werden. Dazu folgende Betrachtungen:&lt;br /&gt;
&lt;br /&gt;
Wenn 2 phasenversetzte  Lichtschranken je Hell-/ Dunkelzyklus bereits 4 Positionen liefern, benötigt die Lochscheibe nur halb so viel &amp;quot;Löcher&amp;quot; wie eine Lochscheibe bei Verwendung nur einer Lichtschranke. Eine 15er Lochscheibe liefert demzufolge 15x4 = 60 Positionen auf 360°, das sind 6° je erfasster Position. Entscheidend ist, an welchem Antriebsteil die Lochscheibe montiert ist und mit welcher Untersetzung zwischen Motor und Abtriebswelle(Rad) gearbeitet wird. Ist die Lochscheibe an der Motorwelle angebracht, würde bei einer angenommenen Untersetzung von 10:1 eine erfasste Position nur 0,6° an der Abtriebswelle ausmachen. &lt;br /&gt;
&lt;br /&gt;
Man muss sich klar machen, welche '''Positioniergenauigkeit''' nötig ist. Dabei gilt: Auslegung so genau wie nötig, nicht wie möglich. Weiter muss geklärt werden, wo man die Lochscheibe sinnvoll anbringt. Sie darf im Betrieb weder verschmutzt oder beschädigt werden. Fahrmodelle ziehen Staub, Haare etc. gern an, gut beraten ist man mit einer '''verkapselten Optomechanik'''. Ein weiterer Faktor ist die '''Drehzahl''' (im Leerlauf am höchsten) des Motors, weil diese die Frequenz der abzutastenden Signale beeinflusst. Zwischen Drehzahl n [U/min], Frequenz f [Hz] und Teilung T besteht folgender Zusammenhang:&lt;br /&gt;
&lt;br /&gt;
'''f = n * T / 60 s'''&lt;br /&gt;
&lt;br /&gt;
Beispiel: Ein Motor dreht im Leerlauf mit 2370 U/min und hat eine Lochscheibe mit Teilung = 12 an der Motorwelle. Die Frequenz der abzutastenden Signale einer Lichtschranke soll ermittelt werden. (oben im Osszillogramm dargestellt)&lt;br /&gt;
&lt;br /&gt;
'''f = 2370 * 12 / 60 s'''&lt;br /&gt;
&lt;br /&gt;
'''f = 474 Hz'''&lt;br /&gt;
&lt;br /&gt;
Eine Lichtschranke liefert also ein Rechtecksignal mit f = 474 Hz. Jetzt muss noch das Signal der zweiten Lichtschranke um 90° versetzt darübergelegt werden. Bei idealen Pegeln sind in einer Periode 4 Schaltzustände abzutasten, also muss die Abtastfrequenz mindestens 4-fach über der Grundfrequenz liegen. Da es in der Praxis aber keine idealen Pegel gibt, muss die Abtastfrequenz noch höher ausgelegt werden. Betrachten wir noch mal das Osszillogrammm weiter oben:&lt;br /&gt;
&lt;br /&gt;
Es fällt auf, das die Zeiten nicht exakt gleich sind, die Zustandszeiten 1 und 3 sind etwas länger als 2 und 4. Das liegt an der Einstellung des Abstandes beider Lichtschranken zueinander, die Phasenlage ist hier nicht genau 90°. Außerdem sind Lochscheibe und Lichtschranken mit kleinen Unregelmäßikeiten, Streuungen, Anstiegs- und Abfallzeiten behaftet, so dass es in einer Periode auch Zeiten gibt, die nicht eindeutig einem der 4 genannten Zustände entsprechen. Für eine sichere Abtastung ist deshalb von der kürzesten (= ungünstigsten) Schaltzeit auszugehen, hier sind es ca. 0,4 Millisekunden, das entspricht 2,5 kHz. Jeder Zustand sollte vom µController sicherheitshalber schon 3 bis 4 mal abgetastet werden, so das wir für das Beispiel mindestens ca. 10 kHz Abtastfrequenz einplanen müssen. Als Orientierungshilfe gilt:&lt;br /&gt;
&lt;br /&gt;
'''Abtastfrequenz &amp;gt;= 20 * Frequenz Lichtschranke'''&lt;br /&gt;
&lt;br /&gt;
Entsprechend der gewünschten Positioniergenauigkeit und Drehzahl kann nun die Teilung der Lochscheibe so gewählt werden, das die Lichtschrankensignale vom µController abgetastet werden können. Da Kaufteile aus dem Industriebereich oft eine recht hohe Teilung vorgeben, ist es manchmal besser, mit kleineren Teilungen anzufangen. Rechts sind Vorlagen, die man sich auf Folien ausdrucken kann.(Nähere Beschreibung im Praxis-Teil)&lt;br /&gt;
&lt;br /&gt;
Die Abtastung muss sicher sein, auch wenn das Hauptprogramm gerade mit anderen Dingen als der Lochscheibenauswertung beschäftigt ist. Man kann zwar die Lochscheibe vom Hauptprogramm durchaus mit abfragen lassen, aber dann sollten keine anderen zeitraubenden Prozeduren darin enthalten sein. Ist nur ein Zustandswechsel übersehen und ausgelassen wurden, geht es erst an der nachfolgenden gleichen Hell-/Dunkel-Kombination weiter und der Contoller verzählt sich um 4 Inkremente! Deshalb sollte die TimerInterrupt-Variante vorgezogen oder die Abtastung in einen separaten µController ausgelagert werden.&lt;br /&gt;
&lt;br /&gt;
Der Positionsbereich muss schließlich auch in einer Variablen dargestellt werden. Im Beispiel mit Teilung =12 wird der Positionzähler bei einer Motorumdrehung um 48 Inkremente hochgezählt. Bei 2370 U/min wäre eine 16Bit-Variable nach ca. 34 Sekunden übergelaufen. Demzufolge ist auch das Speichervolumen der Positionsvariablen dem tatsächlichen Fahrbereich anzupassen. Man kann auch Ober-/ Untergrenzen definieren, die bei Erreichen den Antrieb anhalten. Somit wird ein mechanisches Überfahren von Endlagen oder ein logisches Überlaufen von Variablen verhindert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Zusammenfassung:'''&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|&lt;br /&gt;
# Welche Positionsgenauigkeit brauch ich?&lt;br /&gt;
# Sind Lochscheibe und Optik vor Störeinflüssen geschützt?&lt;br /&gt;
# Welche maximale Drehzahl muss noch sicher abgetastet werden?&lt;br /&gt;
# Frequenz Lichtschranke anpassen: Hohe Drehzahl mit kleiner Teilung / geringe Drehzahl mit großer Teilung&lt;br /&gt;
# Phasenlage richtig eingestellt? Optimal sind 90°&lt;br /&gt;
# Positionsvariable mit genügend Speichervolumen?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Kalibrierung ==&lt;br /&gt;
&lt;br /&gt;
Im einfachsten Fall fährt man seinem Antrieb auf eine Referenzmarke (Nonius, Paßstift o.ä.) und setzt dort den Positionszähler zurück. &lt;br /&gt;
&lt;br /&gt;
Wer es noch genauer will, muß auch noch die Lochscheibe in eine definierte Ausgangsstellung bringen. Dazu kann man die Lichtschrankensignale mit 2 LEDs optisch anzeigen. In der Kalibrierstellung müssen dann der Antrieb auf der Refernzmarke stehen und beide LEDs leuchten. Als Referenzmarke kann natürlich auch eine zusätzliche Lichtschranke dienen, die eine kleine Bohrung am Antrieb erkennt. Wichtig ist, dass die Referenzmarke nur einmal und eindeutig am Antrieb angebracht ist.&lt;br /&gt;
&lt;br /&gt;
== Geschwindigkeit und Beschleunigung ==&lt;br /&gt;
&lt;br /&gt;
Geschwindigkeit wird meist in [m/s], [km/h] oder [mph] ausgedrückt, also der Wegstrecke je Zeiteinheit. Im µController interessieren uns diese Einheiten erst mal nicht, hier werden Inkremente je Zeiteinheit gezählt. Die Zeitintervalle, in denen die Inkremente ausgewertet werden, liefert wieder ein TimerInterrupt. Dieser ist mit deutlich längeren Zyklen auszulegen, damit auch genügend Inkremente je Zyklus gezählt werden können. Im Code-Beispiel unten werden bei 16Mhz CPU-Takt die Vorteiler 1 und 1024 für die TimerInterrupt´s verwendet: Timer 0 mit Prescaler =1024 für die Geschwindigkeitsberechnung mit ca. 61 Hz und Timer 2 mit Prescaler =1 für die Abtastung der Lichtschranken mit 62,5 kHz. Die Geschwindigkeitsmessung wurde mit 12er, 15er und 18er Teilung getestet. In der ISR des Timer_0 Overflow wird die Differenz aus aktueller Position und der Position des vergangenen Zyklus gebildet. Da diese Wegdifferenz in definierten Zeitabständen ermittelt wird, hat man hier bereits die Geschwindigkeit in n Inkremente je 0,01638 Sekunden. Mit dieser etwas abstrakten Geschwindigkeitseinheit wird im Hauptprogramm der Motor gesteuert.&lt;br /&gt;
&lt;br /&gt;
Das gleiche Verfahren ist auch für die Beschleunigung anwendbar. Die Beschleunigung ist die Geschwindigkeitsänderung je Zeiteinheit. In der ISR des Timer_0 Overflow kann die Differenz aus aktueller Geschwindigkeit und der Geschwindigkeit des vergangenen Zyklus gebildet werden, um so die Beschleunigung zu erhalten. Die Einheit ist wieder etwas ungewohnt: Inkremente je 0,01638 Sekunden in 0,01638 Sekunden, also Inkremente/Quadratsekunden. Voraussetzung für eine vernünftige Beschleunigungsermittlung ist, das eine genügend hohe Auflösung der Geschwindigkeit vorliegt(=hohe Teilung der Lochscheibe). Ansonsten sind die ermittelten Werte zu klein und liegen, je nach Trägheit des Motors, fast immer bei 0, 1, 2 oder maximal 3.&lt;br /&gt;
&lt;br /&gt;
Vorteil der Differenzmethode ist, man kann die Geschwindigkeit in einer 8Bit-Variable mit Vorzeichen ausdrücken. Die Werte des Beispieles lagen je nach Teilung zwischen -50 und +50 und sind für die Motorsteuerung ausreichend. Bessere Auflösung erfordert höhere Teilung, höhere Abtastrate, höhere CPU-Frequenz.&lt;br /&gt;
&lt;br /&gt;
== Praxis==&lt;br /&gt;
&lt;br /&gt;
=== Herstellung der Lochscheibe ===&lt;br /&gt;
Für eigene Projekte ist es mitunter schwer, Lochscheiben in passender Größe und Teilung zu finden. Oft müssen dann Kompromisse in der Drehzahlsteuerung oder Positionierung gemacht werden, weil die vielleicht günstigere Teilung nicht zu beschaffen ist. &lt;br /&gt;
&lt;br /&gt;
Hier wird deshalb ein Selbstbau von preiswerten Lochscheiben vorgestellt: Man trägt in einer Excel-Tabelle z.B. 18 mal die Zahl 20 ein und markiert diesen Zellbereich. Anschließend erstellt man mit dem Diagramm-Assistent ein Ring-Diagramm. Darin muss man nun jeden Datenpunkt einzeln formatieren und abwechslend die Farbe schwarz und weiß zuordnen. Markiert man die komplette Datenreihe, kann man unter 'Formatieren'&amp;gt;'Optionen' auch die Innenringgröße einstellen. Dieses Ring-Diagramm kann nun beliebig kopiert und vergößert oder verkleinert werden, auch die Datenreihe kann auf z.B. 24x15 oder 30x12 angepasst werden. So lassen sich auf einer A4-Seite einige Dutzend Lochscheiben in allen Größen und Teilungen herstellen. Das fertige Arbeitsblatt muss nun noch mit geeigneter Tinte auf Folie ausgedruckt werden. Den Drucker muss man möglichst auf satte Farbe und kräftgen Kontrast einstellen. Zum Schluß wird die ausgedruckte Folie mit A4- Laminierfolie verstärkt, wer kein Laminiergerät hat, geht in einen Copy-Shop o.ä. &lt;br /&gt;
&lt;br /&gt;
Die so gewonnenen Lochscheiben werden nun ausgeschnitten und bei Bedarf mit einem Heißluftgerät noch etwas &amp;quot;nachgebacken&amp;quot;, bevor sie im eigenen Projekt mit Kraftkleber auf ein kleines Rad aufgeklebt werden. Hierbei auf gute Zentrierung achten, damit die Lochscheibe möglichst rund läuft. Sekundenkleber ist deshalb ungeeignet, weil kaum Zeit für Korrektur und Einstellung bleibt.&lt;br /&gt;
&lt;br /&gt;
=== Anpassen der Lichtschranke ===&lt;br /&gt;
&lt;br /&gt;
Baustelle:&lt;br /&gt;
&lt;br /&gt;
Fotos, Anregungen zum Nachbau, Beschaffung, Erfahrungen&lt;br /&gt;
&lt;br /&gt;
weiterführende Informationen:&lt;br /&gt;
[http://de.wikipedia.org/wiki/Inkrementalgeber Inkrementalgeber]&lt;br /&gt;
&lt;br /&gt;
=== Quelcode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//Deklaration global&lt;br /&gt;
volatile uint8_t Zust_Li;            //Zustandsmerker Position linker Motor&lt;br /&gt;
volatile uint16_t Li_Inkr;           //aktuelle Position linker Motor&lt;br /&gt;
volatile uint16_t old_Li_Inkr;       //Position im vorangegangenen Takt&lt;br /&gt;
volatile int8_t Speed_Li_Ist;        //Wegänderung je Takt, in ISR Timer 0&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
// Interrupt-Service-Routine  Timer_0 Overflow&lt;br /&gt;
SIGNAL (SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
  // ISR-Code  61,035 Pro Sekunde&lt;br /&gt;
  Timeout++;&lt;br /&gt;
  Speed_Li_Ist = Li_Inkr - old_Li_Inkr;&lt;br /&gt;
  old_Li_Inkr = Li_Inkr;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Interrupt-Service-Routine  Timer_2 Overflow&lt;br /&gt;
SIGNAL (SIG_OVERFLOW2)&lt;br /&gt;
{&lt;br /&gt;
  // ISR-Code  62.5 kHz&lt;br /&gt;
  // 4 Zustaende durch jeweils 1 Bit repräsentiert (1,2,4,8)&lt;br /&gt;
  // Lichtschranke A liegt an Port A.0&lt;br /&gt;
  // Lichtschranke B liegt an Port A.1&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 1) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 2;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 1) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 8;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 2) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 4;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 2) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 1;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 4) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 8;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 4) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 2;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 8) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 1;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 8) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 4;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
//Init&lt;br /&gt;
TCCR2 |= (1&amp;lt;&amp;lt;CS20);                  //Prescaler = 1 (16MHz/1 = 16000000) -&amp;gt;&lt;br /&gt;
                                     //16000000/256 -&amp;gt; 62500 Interrupts je Sekunde&lt;br /&gt;
&lt;br /&gt;
TCCR0 |= (1&amp;lt;&amp;lt;CS02)|(1&amp;lt;&amp;lt;CS00);        //Prescaler = 1024  (16000000 / 1024 = 15625) -&amp;gt;&lt;br /&gt;
                                     //15625/256 = 61,035  -&amp;gt; 61 Interrupts je Sekunde&lt;br /&gt;
&lt;br /&gt;
TIMSK |= (1&amp;lt;&amp;lt;TOIE0)|(1&amp;lt;&amp;lt;TOIE2);      //Timer Overflow Interrupt Enablae für Timer 0 und 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Li_Inkr = 32000;Zust_Li = 1;         // Kalibrierstellung bei 32000&lt;br /&gt;
sei();                               // Interrupts aktivieren&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  while(1)&lt;br /&gt;
  {&lt;br /&gt;
&lt;br /&gt;
  // hier kann Position und Geschwindigkeit ausgewertet werden&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
= Vor und Nachteile der Messmethoden=&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Beispiel_Drehzahlmessung_mit_Drehgeber&amp;diff=17472</id>
		<title>Beispiel Drehzahlmessung mit Drehgeber</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Beispiel_Drehzahlmessung_mit_Drehgeber&amp;diff=17472"/>
				<updated>2011-06-07T16:23:52Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Messen der Drehzahl nach jedem Impuls */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Sensoren]] &lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Motoren]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ermitteln der Drehzahl und Wegstrecke in Abhängigkeit einer Winkeländerung oder Impulsfolge in einer Abgelaufenen Zeit&lt;br /&gt;
&lt;br /&gt;
* Messen der Drehzahl nach jedem Impuls, also in Abhängigkeit einer Winkeländerung.&lt;br /&gt;
* Messen der Drehzahl durch Zählen der Impulse nach Ablauf einer bestimmten Zeit. &lt;br /&gt;
* Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln&lt;br /&gt;
{{Ausbauwunsch|Mehr Grundlagen und vor allem mal praktische Programmbeispiele / Algorithmen etc.}}&lt;br /&gt;
= Messen der Drehzahl nach jedem Impuls =&lt;br /&gt;
&lt;br /&gt;
Dieser Teil beschäftigt sich u.a. mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und [[Gabellichtschranke]] berechnet über die Periodendauer ohne Drehrichtungserkennung.&lt;br /&gt;
[[Bild:GP1S23 Testaufbau.JPG|thumb| Testaufbau mit einer 32er Lochscheibe ]]&lt;br /&gt;
[[Bild:183015_LB_00_FB.EPS_250.jpg|thumb|GP1S23 Gabellichtschranke Bild: Conrad Electronic ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Am einfachsten ist Impulse direkt an einer Bürste eines Motors zu zählen. Siehe dazu: http://www.roboternetz.de/community/...einem-DC-Motor .&lt;br /&gt;
&lt;br /&gt;
Die [http://de.wikipedia.org/wiki/Winkelgeschwindigkeit Winkelgeschwindigkeit] ist die Winkeländerung pro Zeiteinheit. Mit der Lichtschranke und den geometrischen Daten der Lochscheibe kann man nun relativ einfach die Zeit für eine bestimmte Winkeländerung messen. &lt;br /&gt;
Die Lochscheibe gibt uns die Winkeländerung bei einer Periode vor, bei einer 32er Lochscheibe wären das 11,25° pro Periode , wie in den Bildern vom Oszilloskop zu sehen ändert sich natürlich bei Änderung der Drehzahl die Periodendauer, die Winkeländerung pro Periode ist aber konstant da diese durch die Lochscheibe vor gegeben ist. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Bild:GP1S23_signal_langsam.png|Signal der Lichtschranke bei langsamer Drehzahl &lt;br /&gt;
Bild:GP1S23_signal_schnell.PNG |Signal der Lichtschranke bei schneller Drehzahl &lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um die Periodendauer zu messen verwende ich den ICP1 (Input Capture Pin) eines Atmega8 der bei steigender Flanke den Timer1 ausliest und in das ICR1 Register schreibt. Läuft der Mikrocontroller auf 8Mhz und wir stellen den Vorteiler des Timers auf 8 so bekommen wir die Periodendauer in µs als Wert.&lt;br /&gt;
&lt;br /&gt;
== Auslegen der Lochscheibe ==&lt;br /&gt;
&lt;br /&gt;
In den meisten Fällen definieren der mechanische Aufbau den Durchmesser der Lochscheibe und die Drehzahl die Teilung (Anzahl der Löcher). Der µContoller und die Gabellichtschranke müssen die Impulse auch erfassen und verarbeiten können. Wenn man das Drehzahlband abschätzen kann ist es hilfreich, sich schon Gedanken um die Programmierung zu machen, denn bei hohen Drehzahlen springt der µC jedes mal in die Interrupt Service Routine rein, sofern man es so programmiert wie im Beispiel. Bei hohen Drehzahlen sollte die Teilung somit gröber, bei niedriger Drehzahl die Teilung feiner sein. &lt;br /&gt;
&lt;br /&gt;
[[Bild:Drehscheibe20mm.png|400px|thumb|left|Lochscheibe abgerollt mit idealisiertem Signal ]]&lt;br /&gt;
&lt;br /&gt;
== Berechnungen ==&lt;br /&gt;
&lt;br /&gt;
Hier folgt nun die Berechnung über die Periodendauer, beachten sollte man das im [http://de.wikipedia.org/wiki/Bogenma%C3%9F Bogenmaß] gerechnet wird, ein Winkel mit dem Bogenmaß 1 rad hat ein Gradmaß von ca. 57,3°. 11.25° sind also ca. 0,196 rad, das führt später natürlich zu unschönen Rechenoperationen im µC, Stichwort [http://www.mikrocontroller.net/articles/Festkommaarithmetik Festkommaarithmetik]. &lt;br /&gt;
&lt;br /&gt;
Nach dem Umstellen kommt man aber auf eine recht handliche Formel &amp;lt;math&amp;gt;n = \frac{\varphi }{dt \cdot 360}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es ist auch eine Überlegung wert, ob man die Drehzahl nicht umrechnet sondern mit der Periodendauer arbeitet. Das ist zwar nicht so geläufig aber das stört den µController nicht. Mit einem Kalkulationsprogramm kann man die Umrechnung von Periodendauer in Drehzahl auch extern vornehmen. &lt;br /&gt;
&lt;br /&gt;
Man sollte sich auch klar machen, das zumindest ein 8-Bit Prozessor am besten mit '''Ganzzahlen''' zwischen 0 und 255 oder 0 und 65535 zurechtkommt. Für die Teilung der Lochscheibe bieten sich deshalb Werte wie 90, 72, 45, 36, 30, 24, 20, 18, 15, 12, 10 und 8 an. Verwendet man an Stelle der dargestellten 32er Lochscheibe eine 30er oder 36er Scheibe, kann man zumindest mit ganzzahligen Gradzahlen rechnen. &amp;quot;Krumme Werte&amp;quot; wie [http://de.wikipedia.org/wiki/Kreiszahl Pi = 3,1415...], [http://de.wikipedia.org/wiki/Radiant_%28Einheit%29 Radiant = 57,29577...°] usw. sollten eine seltene Ausnahme in der Programmierung sein.&lt;br /&gt;
&lt;br /&gt;
= Messen der Drehzahl durch zählen der Impulse =&lt;br /&gt;
&lt;br /&gt;
Dieser Teil beschäftigt sich mit der Optischen Drehzahlmessung mit Hilfe einer Lochscheibe und [[Gabellichtschranke]] berechnet über die die Anzahl der Impulse in einer gewissen Zeit.&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Berechnung==&lt;br /&gt;
&lt;br /&gt;
= Richtung, Geschwindigkeit und Position mit Doppellichtschranke ermitteln =&lt;br /&gt;
Dieser Teil beschäftigt sich mit der Optischen Drehzahl- und Geschwindigkeitsmessung sowie der Erfassung von Drehrichtung und zurückgelegter Position mit Hilfe einer Lochscheibe und 2 Gabellichtschranken. Hierfür werden Quadratursignale in definierten Zeitabständen ausgewertet.&lt;br /&gt;
 &lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Für kontrollierte Bewegungen ist es mitunter wichtig, auch die Drehrichtung/Richtungswechsel und Position auszuwerten. Eine Lochscheibe mit einer Gabellichtschranke liefert lediglich Rechteckimpulse, egal wie rum sich die Lochscheibe bewegt. Bringt man eine zweite Gabellichtschranke an der gleichen Lochscheibe leicht versetzt an, bekommt man auch die Drehrichtung mit. Diese Methode ist altbekannt, simpel und leicht nachzubauen. Wenn man die Drehrichtung kennt, ist auch die Position kein Problem mehr. Ausgehend von einer Kalibrierposition können bei Vorwärtsbewegung Inkremente hochgezählt oder bei Rückwärtsbewegung runtergezählt werden. &lt;br /&gt;
&lt;br /&gt;
Interessierte nehmen dazu mal eine PC-Maus mit Kugelantrieb zur Hand. Darin findet man zwei kleine Lochscheiben, die für die X- und Y-Richtung die Impulse erzeugen. Durch spezielle Gabellichtschranken mit 2 phasenversetzten Ausgängen wird auch die Drehrichtung erkannt. &lt;br /&gt;
&lt;br /&gt;
Das selbe Prinzip ist in linearer Form auch in PC-Druckern zu finden: Entlang des Wagenrücklaufes ist ein transparentes Kunsstoffband gespannt, auf dem winzig kleine Streifenmuster aufgebracht sind. Diese werden von einer Gabellichtschranke mit 2 Ausgängen erkannt und so die Wagenposition gesteuert.&lt;br /&gt;
&lt;br /&gt;
Aber es geht natürlich noch einfacher...&lt;br /&gt;
&lt;br /&gt;
== Zwei Lichtschranken liefern vier Informationen ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:vorwaerts_.jpg|thumb|Zustandsfolge bei Vorwärtsbewegung]]&lt;br /&gt;
[[Bild:rueckwaerts_.jpg|thumb|Zustandsfolge bei Rückwärtsbewegung]]&lt;br /&gt;
[[Bild:2LSZustand.jpg|thumb|2 Lichtschranken (LSA und LSB) liefern phasenversetzte Rechtecksignale. In Vorwärts- und Rückwärtsrichtung ergeben sich unterschiedliche Zustandsfolgen]]&lt;br /&gt;
&lt;br /&gt;
Man nimmt 2 normale Gabellichtschranken und bringt sie so an, das sie im 1,5 fachen Lochabstand die Lochscheibe durchleuchten. Wenn sich Lichtschranke A in der Mitte des Lichtstreifens befindet, ist Lichtschranke B an der Grenze des Schattenstreifens. Nebenstehende Skizzen zeigen die möglichen Zustände beider Lichtschranken bei Vorwärts- und Rückwärtsbewgung der Lochscheibe. Wichtig ist hierbei, das die Lochscheibe in gleich breite Licht- und Schattensegmente eingeteilt ist und die Lichtschranke(n) einen möglichst haarfeinen Lichtstrahl besitzt. Die Signale der Fototransistoren sollten verstärkt und gegebenenfalls mit TTL-Bausteinen zu korrekten High- und Low-Pegeln aufbereitet werden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es ergeben sich nun folgende Kombinationen:&lt;br /&gt;
&lt;br /&gt;
* Zustand 1:    LSA =   hell und LSB =   hell&lt;br /&gt;
* Zustand 2:    LSA =   hell und LSB = dunkel&lt;br /&gt;
* Zustand 3:    LSA = dunkel und LSB = dunkel&lt;br /&gt;
* Zustand 4:    LSA = dunkel und LSB =   hell&lt;br /&gt;
&lt;br /&gt;
Dreht man die Lochscheibe weiter, wiederholt sich der Vorgang. Die Zustandsfolge ist 1 &amp;gt; 2 &amp;gt; 3 &amp;gt; 4 &amp;gt; 1 &amp;gt; 2 &amp;gt; 3 &amp;gt; 4 &amp;gt;  usw.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bei entgegengesetzter Drehrichtung ändert sich diese Reihenfolge. Betrachtet man wieder vom Zustand 1 ausgehend die Gegenrichtung, ergeben sich nun diese Kombinationen:&lt;br /&gt;
&lt;br /&gt;
* Zustand 1:    LSA =   hell und LSB =   hell&lt;br /&gt;
* Zustand 4:    LSA = dunkel und LSB =   hell&lt;br /&gt;
* Zustand 3:    LSA = dunkel und LSB = dunkel&lt;br /&gt;
* Zustand 2:    LSA =   hell und LSB = dunkel&lt;br /&gt;
&lt;br /&gt;
Die Zustandsfolge in Gegenrichtung lautet dann: 1 &amp;lt; 4 &amp;lt; 3 &amp;lt; 2 &amp;lt; 1 &amp;lt; 4 &amp;lt; 3 &amp;lt; 2 &amp;lt;  usw.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit diesem Wissen ist es nun ein Kinderspiel, auch die Änderung der Drehrichtung festzustellen. Dazu muss der letzte Zustand in einer Variable gespeichert und mit dem neu erkannten Zustand verglichen werden. Folgt nach Zustand 1 der Zustand 2, so ist es eine Vorwärtsbewegung. Folgt dem Zustand 1 der Zustand 4, so ist es eine Rückwärtsbewegung. Gleiches Prinzip gilt auch für die restlichen Zustände 2, 3 und 4.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Positionsüberwachung ==&lt;br /&gt;
&lt;br /&gt;
Von jedem der 4 Zustände gibt es also zwei zu unterscheidende Fälle: Vorwärts und Rückwärts. Insgesamt müssen demzufolge 8 Bedingungen zyklisch abgetastet und ein Positionszähler entsprechend inkrementiert oder dekrementiert werden und schon hat man eine exakte Streckeninformation. In Worte gefasst ergibt sich folgende Logik:&lt;br /&gt;
&lt;br /&gt;
Ausgangszustand: Beide Lichtschranken sind aus (A=0 UND B=0) und Zustand =1&lt;br /&gt;
&lt;br /&gt;
* WENN (Zustand=1 UND A=0 UND B=1) DANN: Setze Zustand=2, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=1 UND A=1 UND B=0) DANN: Setze Zustand=4, Position dekrementieren, Rück&lt;br /&gt;
* WENN (Zustand=2 UND A=1 UND B=1) DANN: Setze Zustand=3, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=2 UND A=0 UND B=0) DANN: Setze Zustand=1, Position dekrementieren, Rück&lt;br /&gt;
* WENN (Zustand=3 UND A=1 UND B=0) DANN: Setze Zustand=4, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=3 UND A=0 UND B=1) DANN: Setze Zustand=2, Position dekrementieren, Rück&lt;br /&gt;
* WENN (Zustand=4 UND A=0 UND B=0) DANN: Setze Zustand=1, Position inkrementieren, Vor&lt;br /&gt;
* WENN (Zustand=4 UND A=1 UND B=1) DANN: Setze Zustand=3, Position dekrementieren, Rück&lt;br /&gt;
[[Bild:Lochscheibe8.jpg|thumb|Lochscheibe 8 ]]&lt;br /&gt;
[[Bild:Lochscheibe10.jpg|thumb|Lochscheibe 10 ]]&lt;br /&gt;
[[Bild:Lochscheibe12.jpg|thumb|Lochscheibe 12 ]]&lt;br /&gt;
[[Bild:Lochscheibe15.jpg|thumb|Lochscheibe 15 ]]&lt;br /&gt;
[[Bild:Lochscheibe18.jpg|thumb|Lochscheibe 18 ]]&lt;br /&gt;
[[Bild:Lochscheibe20.jpg|thumb|Lochscheibe 20 ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Prüfung muss ständig wiederholt werden, damit alle Pegelwechsel der beiden Lichtschranken erfasst werden. Nur so ist es möglich, die exakte Position zu verfolgen. Dafür bieten sich 2 Möglichkeiten: Entweder die Prüfung wird im Hauptprogramm ständig durchlaufen (Polling) oder ein Timer-Interrupt tastet regelmäßig die Lichtschranken ab. Hier soll nur die zweite, also Interruptvariante betrachtet werden, weil sie mehr Vorteile bringt. Weiter unten im Artikel ist dazu ein Beispiel in Sprache C zu finden. &lt;br /&gt;
&lt;br /&gt;
Zuvor muss aber eine sinnvolle Auslegung von Lochscheibe, Drehzahl und Positionsbereich gefunden und in Einklang mit den Ressourcen des verwendeten µControlles gebracht werden. Dazu folgende Betrachtungen:&lt;br /&gt;
&lt;br /&gt;
Wenn 2 phasenversetzte  Lichtschranken je Hell-/ Dunkelzyklus bereits 4 Positionen liefern, benötigt die Lochscheibe nur halb so viel &amp;quot;Löcher&amp;quot; wie eine Lochscheibe bei Verwendung nur einer Lichtschranke. Eine 15er Lochscheibe liefert demzufolge 15x4 = 60 Positionen auf 360°, das sind 6° je erfasster Position. Entscheidend ist, an welchem Antriebsteil die Lochscheibe montiert ist und mit welcher Untersetzung zwischen Motor und Abtriebswelle(Rad) gearbeitet wird. Ist die Lochscheibe an der Motorwelle angebracht, würde bei einer angenommenen Untersetzung von 10:1 eine erfasste Position nur 0,6° an der Abtriebswelle ausmachen. &lt;br /&gt;
&lt;br /&gt;
Man muss sich klar machen, welche '''Positioniergenauigkeit''' nötig ist. Dabei gilt: Auslegung so genau wie nötig, nicht wie möglich. Weiter muss geklärt werden, wo man die Lochscheibe sinnvoll anbringt. Sie darf im Betrieb weder verschmutzt oder beschädigt werden. Fahrmodelle ziehen Staub, Haare etc. gern an, gut beraten ist man mit einer '''verkapselten Optomechanik'''. Ein weiterer Faktor ist die '''Drehzahl''' (im Leerlauf am höchsten) des Motors, weil diese die Frequenz der abzutastenden Signale beeinflusst. Zwischen Drehzahl n [U/min], Frequenz f [Hz] und Teilung T besteht folgender Zusammenhang:&lt;br /&gt;
&lt;br /&gt;
'''f = n * T / 60 s'''&lt;br /&gt;
&lt;br /&gt;
Beispiel: Ein Motor dreht im Leerlauf mit 2370 U/min und hat eine Lochscheibe mit Teilung = 12 an der Motorwelle. Die Frequenz der abzutastenden Signale einer Lichtschranke soll ermittelt werden. (oben im Osszillogramm dargestellt)&lt;br /&gt;
&lt;br /&gt;
'''f = 2370 * 12 / 60 s'''&lt;br /&gt;
&lt;br /&gt;
'''f = 474 Hz'''&lt;br /&gt;
&lt;br /&gt;
Eine Lichtschranke liefert also ein Rechtecksignal mit f = 474 Hz. Jetzt muss noch das Signal der zweiten Lichtschranke um 90° versetzt darübergelegt werden. Bei idealen Pegeln sind in einer Periode 4 Schaltzustände abzutasten, also muss die Abtastfrequenz mindestens 4-fach über der Grundfrequenz liegen. Da es in der Praxis aber keine idealen Pegel gibt, muss die Abtastfrequenz noch höher ausgelegt werden. Betrachten wir noch mal das Osszillogrammm weiter oben:&lt;br /&gt;
&lt;br /&gt;
Es fällt auf, das die Zeiten nicht exakt gleich sind, die Zustandszeiten 1 und 3 sind etwas länger als 2 und 4. Das liegt an der Einstellung des Abstandes beider Lichtschranken zueinander, die Phasenlage ist hier nicht genau 90°. Außerdem sind Lochscheibe und Lichtschranken mit kleinen Unregelmäßikeiten, Streuungen, Anstiegs- und Abfallzeiten behaftet, so dass es in einer Periode auch Zeiten gibt, die nicht eindeutig einem der 4 genannten Zustände entsprechen. Für eine sichere Abtastung ist deshalb von der kürzesten (= ungünstigsten) Schaltzeit auszugehen, hier sind es ca. 0,4 Millisekunden, das entspricht 2,5 kHz. Jeder Zustand sollte vom µController sicherheitshalber schon 3 bis 4 mal abgetastet werden, so das wir für das Beispiel mindestens ca. 10 kHz Abtastfrequenz einplanen müssen. Als Orientierungshilfe gilt:&lt;br /&gt;
&lt;br /&gt;
'''Abtastfrequenz &amp;gt;= 20 * Frequenz Lichtschranke'''&lt;br /&gt;
&lt;br /&gt;
Entsprechend der gewünschten Positioniergenauigkeit und Drehzahl kann nun die Teilung der Lochscheibe so gewählt werden, das die Lichtschrankensignale vom µController abgetastet werden können. Da Kaufteile aus dem Industriebereich oft eine recht hohe Teilung vorgeben, ist es manchmal besser, mit kleineren Teilungen anzufangen. Rechts sind Vorlagen, die man sich auf Folien ausdrucken kann.(Nähere Beschreibung im Praxis-Teil)&lt;br /&gt;
&lt;br /&gt;
Die Abtastung muss sicher sein, auch wenn das Hauptprogramm gerade mit anderen Dingen als der Lochscheibenauswertung beschäftigt ist. Man kann zwar die Lochscheibe vom Hauptprogramm durchaus mit abfragen lassen, aber dann sollten keine anderen zeitraubenden Prozeduren darin enthalten sein. Ist nur ein Zustandswechsel übersehen und ausgelassen wurden, geht es erst an der nachfolgenden gleichen Hell-/Dunkel-Kombination weiter und der Contoller verzählt sich um 4 Inkremente! Deshalb sollte die TimerInterrupt-Variante vorgezogen oder die Abtastung in einen separaten µController ausgelagert werden.&lt;br /&gt;
&lt;br /&gt;
Der Positionsbereich muss schließlich auch in einer Variablen dargestellt werden. Im Beispiel mit Teilung =12 wird der Positionzähler bei einer Motorumdrehung um 48 Inkremente hochgezählt. Bei 2370 U/min wäre eine 16Bit-Variable nach ca. 34 Sekunden übergelaufen. Demzufolge ist auch das Speichervolumen der Positionsvariablen dem tatsächlichen Fahrbereich anzupassen. Man kann auch Ober-/ Untergrenzen definieren, die bei Erreichen den Antrieb anhalten. Somit wird ein mechanisches Überfahren von Endlagen oder ein logisches Überlaufen von Variablen verhindert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Zusammenfassung:'''&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|&lt;br /&gt;
# Welche Positionsgenauigkeit brauch ich?&lt;br /&gt;
# Sind Lochscheibe und Optik vor Störeinflüssen geschützt?&lt;br /&gt;
# Welche maximale Drehzahl muss noch sicher abgetastet werden?&lt;br /&gt;
# Frequenz Lichtschranke anpassen: Hohe Drehzahl mit kleiner Teilung / geringe Drehzahl mit großer Teilung&lt;br /&gt;
# Phasenlage richtig eingestellt? Optimal sind 90°&lt;br /&gt;
# Positionsvariable mit genügend Speichervolumen?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Kalibrierung ==&lt;br /&gt;
&lt;br /&gt;
Im einfachsten Fall fährt man seinem Antrieb auf eine Referenzmarke (Nonius, Paßstift o.ä.) und setzt dort den Positionszähler zurück. &lt;br /&gt;
&lt;br /&gt;
Wer es noch genauer will, muß auch noch die Lochscheibe in eine definierte Ausgangsstellung bringen. Dazu kann man die Lichtschrankensignale mit 2 LEDs optisch anzeigen. In der Kalibrierstellung müssen dann der Antrieb auf der Refernzmarke stehen und beide LEDs leuchten. Als Referenzmarke kann natürlich auch eine zusätzliche Lichtschranke dienen, die eine kleine Bohrung am Antrieb erkennt. Wichtig ist, dass die Referenzmarke nur einmal und eindeutig am Antrieb angebracht ist.&lt;br /&gt;
&lt;br /&gt;
== Geschwindigkeit und Beschleunigung ==&lt;br /&gt;
&lt;br /&gt;
Geschwindigkeit wird meist in [m/s], [km/h] oder [mph] ausgedrückt, also der Wegstrecke je Zeiteinheit. Im µController interessieren uns diese Einheiten erst mal nicht, hier werden Inkremente je Zeiteinheit gezählt. Die Zeitintervalle, in denen die Inkremente ausgewertet werden, liefert wieder ein TimerInterrupt. Dieser ist mit deutlich längeren Zyklen auszulegen, damit auch genügend Inkremente je Zyklus gezählt werden können. Im Code-Beispiel unten werden bei 16Mhz CPU-Takt die Vorteiler 1 und 1024 für die TimerInterrupt´s verwendet: Timer 0 mit Prescaler =1024 für die Geschwindigkeitsberechnung mit ca. 61 Hz und Timer 2 mit Prescaler =1 für die Abtastung der Lichtschranken mit 62,5 kHz. Die Geschwindigkeitsmessung wurde mit 12er, 15er und 18er Teilung getestet. In der ISR des Timer_0 Overflow wird die Differenz aus aktueller Position und der Position des vergangenen Zyklus gebildet. Da diese Wegdifferenz in definierten Zeitabständen ermittelt wird, hat man hier bereits die Geschwindigkeit in n Inkremente je 0,01638 Sekunden. Mit dieser etwas abstrakten Geschwindigkeitseinheit wird im Hauptprogramm der Motor gesteuert.&lt;br /&gt;
&lt;br /&gt;
Das gleiche Verfahren ist auch für die Beschleunigung anwendbar. Die Beschleunigung ist die Geschwindigkeitsänderung je Zeiteinheit. In der ISR des Timer_0 Overflow kann die Differenz aus aktueller Geschwindigkeit und der Geschwindigkeit des vergangenen Zyklus gebildet werden, um so die Beschleunigung zu erhalten. Die Einheit ist wieder etwas ungewohnt: Inkremente je 0,01638 Sekunden in 0,01638 Sekunden, also Inkremente/Quadratsekunden. Voraussetzung für eine vernünftige Beschleunigungsermittlung ist, das eine genügend hohe Auflösung der Geschwindigkeit vorliegt(=hohe Teilung der Lochscheibe). Ansonsten sind die ermittelten Werte zu klein und liegen, je nach Trägheit des Motors, fast immer bei 0, 1, 2 oder maximal 3.&lt;br /&gt;
&lt;br /&gt;
Vorteil der Differenzmethode ist, man kann die Geschwindigkeit in einer 8Bit-Variable mit Vorzeichen ausdrücken. Die Werte des Beispieles lagen je nach Teilung zwischen -50 und +50 und sind für die Motorsteuerung ausreichend. Bessere Auflösung erfordert höhere Teilung, höhere Abtastrate, höhere CPU-Frequenz.&lt;br /&gt;
&lt;br /&gt;
== Praxis==&lt;br /&gt;
&lt;br /&gt;
=== Herstellung der Lochscheibe ===&lt;br /&gt;
Für eigene Projekte ist es mitunter schwer, Lochscheiben in passender Größe und Teilung zu finden. Oft müssen dann Kompromisse in der Drehzahlsteuerung oder Positionierung gemacht werden, weil die vielleicht günstigere Teilung nicht zu beschaffen ist. &lt;br /&gt;
&lt;br /&gt;
Hier wird deshalb ein Selbstbau von preiswerten Lochscheiben vorgestellt: Man trägt in einer Excel-Tabelle z.B. 18 mal die Zahl 20 ein und markiert diesen Zellbereich. Anschließend erstellt man mit dem Diagramm-Assistent ein Ring-Diagramm. Darin muss man nun jeden Datenpunkt einzeln formatieren und abwechslend die Farbe schwarz und weiß zuordnen. Markiert man die komplette Datenreihe, kann man unter 'Formatieren'&amp;gt;'Optionen' auch die Innenringgröße einstellen. Dieses Ring-Diagramm kann nun beliebig kopiert und vergößert oder verkleinert werden, auch die Datenreihe kann auf z.B. 24x15 oder 30x12 angepasst werden. So lassen sich auf einer A4-Seite einige Dutzend Lochscheiben in allen Größen und Teilungen herstellen. Das fertige Arbeitsblatt muss nun noch mit geeigneter Tinte auf Folie ausgedruckt werden. Den Drucker muss man möglichst auf satte Farbe und kräftgen Kontrast einstellen. Zum Schluß wird die ausgedruckte Folie mit A4- Laminierfolie verstärkt, wer kein Laminiergerät hat, geht in einen Copy-Shop o.ä. &lt;br /&gt;
&lt;br /&gt;
Die so gewonnenen Lochscheiben werden nun ausgeschnitten und bei Bedarf mit einem Heißluftgerät noch etwas &amp;quot;nachgebacken&amp;quot;, bevor sie im eigenen Projekt mit Kraftkleber auf ein kleines Rad aufgeklebt werden. Hierbei auf gute Zentrierung achten, damit die Lochscheibe möglichst rund läuft. Sekundenkleber ist deshalb ungeeignet, weil kaum Zeit für Korrektur und Einstellung bleibt.&lt;br /&gt;
&lt;br /&gt;
=== Anpassen der Lichtschranke ===&lt;br /&gt;
&lt;br /&gt;
Baustelle:&lt;br /&gt;
&lt;br /&gt;
Fotos, Anregungen zum Nachbau, Beschaffung, Erfahrungen&lt;br /&gt;
&lt;br /&gt;
weiterführende Informationen:&lt;br /&gt;
[http://de.wikipedia.org/wiki/Inkrementalgeber Inkrementalgeber]&lt;br /&gt;
&lt;br /&gt;
=== Quelcode ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//Deklaration global&lt;br /&gt;
volatile uint8_t Zust_Li;            //Zustandsmerker Position linker Motor&lt;br /&gt;
volatile uint16_t Li_Inkr;           //aktuelle Position linker Motor&lt;br /&gt;
volatile uint16_t old_Li_Inkr;       //Position im vorangegangenen Takt&lt;br /&gt;
volatile int8_t Speed_Li_Ist;        //Wegänderung je Takt, in ISR Timer 0&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
// Interrupt-Service-Routine  Timer_0 Overflow&lt;br /&gt;
SIGNAL (SIG_OVERFLOW0)&lt;br /&gt;
{&lt;br /&gt;
  // ISR-Code  61,035 Pro Sekunde&lt;br /&gt;
  Timeout++;&lt;br /&gt;
  Speed_Li_Ist = Li_Inkr - old_Li_Inkr;&lt;br /&gt;
  old_Li_Inkr = Li_Inkr;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Interrupt-Service-Routine  Timer_2 Overflow&lt;br /&gt;
SIGNAL (SIG_OVERFLOW2)&lt;br /&gt;
{&lt;br /&gt;
  // ISR-Code  62.5 kHz&lt;br /&gt;
  // 4 Zustaende durch jeweils 1 Bit repräsentiert (1,2,4,8)&lt;br /&gt;
  // Lichtschranke A liegt an Port A.0&lt;br /&gt;
  // Lichtschranke B liegt an Port A.1&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 1) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 2;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 1) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 8;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 2) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 4;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 2) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 1;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 4) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 8;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 4) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 2;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 8) &amp;amp;&amp;amp; ( !(PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0)) )&amp;amp;&amp;amp; ( !( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1)) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr + 1;&lt;br /&gt;
    Zust_Li = 1;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
  if ( (Zust_Li == 8) &amp;amp;&amp;amp; (PINA &amp;amp; (1&amp;lt;&amp;lt;PINA0) )&amp;amp;&amp;amp; ( PINA &amp;amp; (1&amp;lt;&amp;lt;PINA1) ) ){&lt;br /&gt;
    Li_Inkr = Li_Inkr - 1;&lt;br /&gt;
    Zust_Li = 4;&lt;br /&gt;
  } /* end if */&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
int main (void)&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
//Init&lt;br /&gt;
TCCR2 |= (1&amp;lt;&amp;lt;CS20);                  //Prescaler = 1 (16MHz/1 = 16000000) -&amp;gt;&lt;br /&gt;
                                     //16000000/256 -&amp;gt; 62500 Interrupts je Sekunde&lt;br /&gt;
&lt;br /&gt;
TCCR0 |= (1&amp;lt;&amp;lt;CS02)|(1&amp;lt;&amp;lt;CS00);        //Prescaler = 1024  (16000000 / 1024 = 15625) -&amp;gt;&lt;br /&gt;
                                     //15625/256 = 61,035  -&amp;gt; 61 Interrupts je Sekunde&lt;br /&gt;
&lt;br /&gt;
TIMSK |= (1&amp;lt;&amp;lt;TOIE0)|(1&amp;lt;&amp;lt;TOIE2);      //Timer Overflow Interrupt Enablae für Timer 0 und 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Li_Inkr = 32000;Zust_Li = 1;         // Kalibrierstellung bei 32000&lt;br /&gt;
sei();                               // Interrupts aktivieren&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  while(1)&lt;br /&gt;
  {&lt;br /&gt;
&lt;br /&gt;
  // hier kann Position und Geschwindigkeit ausgewertet werden&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
= Vor und Nachteile der Messmethoden=&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Schwingquarz&amp;diff=17468</id>
		<title>Schwingquarz</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Schwingquarz&amp;diff=17468"/>
				<updated>2011-06-02T23:22:34Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Temperaturabhängigkeit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:Schaltzeichen_Quarz.jpg|thumb|Schaltzeichen eines Schwingquarz]]&lt;br /&gt;
Ein Schwingquarz ist ein kleines Plättchen, in einer bestimmten Form aus einem speziellem Quarzkristall geschnitten. Dieses Plättchen erhält zwei Kontakte und wird so in ein luftdichtes Gehäuse montiert, daß es nur durch diese Anschlüsse gehalten wird.&lt;br /&gt;
&lt;br /&gt;
Auf Grund der piezo-elektrischen Eigenschaften des Quarzes führt dieser unter dem Einfluß von elektrischen Wechselspannungen genau definierte Schwingungen aus, wenn die Frequenz der Wechselspannung mit der Eigenfrequenz des Quarzes übereinstimmt. Elektrisch verhält sich der Quarz dann wie ein Schwingkreis mit hoher Güte. Durch externe Kondesatoren kann die Frequenz ein wenig (bis ca. 0,01 %) verändert werden&lt;br /&gt;
&lt;br /&gt;
Für Frequenzen bis etwa 100 MHz sind häufig Grundtonquarze verfügbar. Für höhere Frequenzen (über etwa 20 MHz) werden zum Teil aber auch Obertonquarze angeboten. Die gewünschte Frequenz ist bei diesen Schwingquarzen nicht die niedriegste verfügbare Frequenz (der Grundton), sondern ein ungerades Vielfaches davon (üblich ist das 3- oder 5-Fache, ein Oberton). Durch einen zusätzlichen Schwingkreis muß dann die richtige Resoanzfrequenz ausgewählt werden. Zum direkten Anschluß an Mikrocontroller benötigt man Grundtonquarze.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Schwingquarze kommen überall zur Anwendung, wo eine konstante Frequenz (u.a. als Zeitbasis) gebraucht wird. Sie finden sich z. B. in praktisch allen Sendern, in Quarzuhren, als Taktgeber in allen Arten von Computern sowie in Frequenzzählern und digitalen Signalgeneratoren.   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
[[Bild:Quarze.jpg|thumb|Bauformen verschiedener Schwingquarze und externer Quarzoszillatoren]]&lt;br /&gt;
Der folgende Kommentar ist eigentlich überflüssig, aber gerade dies wird oft fasch verstanden:&amp;lt;br/&amp;gt;'''Ein Schwingquarz alleine bestimmt nur die Frequenz. Er ist weder ein Oszillator noch ein Taktgeber!'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Allgemeines zu Schwingquarzen ==&lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|Für die meisten Verwendungszwecke sind die im Handel erhältlichen Schwingquarze sowie deren Verwendung in den üblichen Oszillatorschaltungen (siehe [[Quarzoszillator]]) völlig ausreichend. Bei speziellen Anforderungen oder dem Entwurf neuer Schaltungen sollte auf jeden Fall vor der Verwendung eines Quarzes das entsprechende Datenblatt des Herstellers zu Rate gezogen werden!&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Temperaturabhängigkeit ===&lt;br /&gt;
Schwingquarze ändern ihr Verhalten und damit auch ihre elektrischen Eigenschaften in Abhängigkeit von der Temperatur. Die Abweichung liegt je nach Qualität bei z.B. 0,2ppm pro °C (aber nicht linear). In der Praxis bedeutet dies im Temperaturbereich von -40°C bis +85°C (Verwendung &amp;quot;normaler&amp;quot; Bauelemente) eine Abweichung von maximal 0,01 % von der nominellen Frequenz. Die ist für die meisten Verwendungszwecke völlig ausreichend!&amp;lt;br/&amp;gt;Für Funkfrequenzeinstellungen und hochgenaue Uhren kann durch die Wahl geeigneter externer Bauelemente eine Korrektur dieses Temperaturverhaltens durchgeführt werden. Alternativ wird die Temperatur konstant gehalten auf z.B. 40°C. Am stabilsten bei variabler Temperatur sind Quarze 7.2 MHz.&lt;br /&gt;
&lt;br /&gt;
=== Leistungsverhalten ===&lt;br /&gt;
*Großleistungsverhalten: Die Amplituden der Schwingungen im Quarzkristall sind proportional zu dem Wechselstrom, der durch den Resonanzwiderstand (Verlustwiderstand) des Quarzes fließt. Steigt dieser Strom stark an, kommt es zuerst zu Änderungen in den elastischen Eigenschaften des Quarzes, danach zu starker Erwärmung durch die Verlustleistung im Resonanzwiderstand. Beide Situationen führen zu bleibenden Veränderungen der Resonanzfrequenz. Steigt der Strom weiter, wird der Quarz nach Überschreiten der inneren Festigkeit des Kristallgitters zerstört.&amp;lt;br/&amp;gt; Quarze mit kleinen Oberflächen oder mit kleinen Elektroden (SMD) sind weniger belastbar wie größere Quarze. Quarze mit großer Güte Q sind ebenfalls weniger belastbar wie Quarze mit kleiner Güte.&lt;br /&gt;
*Kleinleistungsverhalten: Auf Grund von Fertigungstoleranzen und -fehlern kann es im Bereich kleinster Belastungen (unter 1mW) eines Quarzes zu teils gravierenden Abweichungen des Resonanzwiderstandes kommen. Dies zeigt sich häufig in einem schwachen oder gar fehlenden Anschwingen des Quarzoszillators im unbelasteten Zustand. Ein solcher Quarz ist definitv ein Produktionsfehler.&amp;lt;br/&amp;gt;Der Anwender eines solchen Quarzes kann entweder seine Schaltung überarbeiten (Anschwingen unter größerer Last), oder den Quarz austauschen.&lt;br /&gt;
&lt;br /&gt;
=== Alterung ===&lt;br /&gt;
Durch das verwendete Material sowie durch die verwendeten konstruktions- und herstellungsbedingten Verfahren verändert sich die Resonanzfrequenz eines Schwingquarzes kontinuierlich über einen längeren Zeitraum, der Quarz &amp;quot;altert&amp;quot;. Auch ist diese Alterung temperaturabhängig, bei hohen oder niedrigen Temperaturen altert ein Quarz schneller. Hierbei beträgt die Zunahme der Alterung etwa 10% pro 10°C, bei 85°C altert ein Quarz etwa doppelt so schnell wie bei 25°C.&amp;lt;br/&amp;gt;Die Alterungsrate bei typischen Großserien-Quarzen liegt im Bereich von etwa 2ppm pro Jahr. Diese Alterung ist also für normale Anwendungegebiete vernachlässigbar, für hochgenaue Anwendungen können stabilisierte Schwingquarze mit einer Alterungrate von unter 0,1ppm pro Jahr eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Uhrenquarze ===&lt;br /&gt;
Speziell für Anwendungen mit sehr geringer Leistungsaufnahmen gibt es Quarze für die relativ niedrige Frequenz von 32678 Hz. Diese sind intern in Form einer Stimmgabel aufgebaut, verhalten sich aber sonst ähnlich wie die plattenförmigen Quarze.&lt;br /&gt;
&lt;br /&gt;
== Verweise ==&lt;br /&gt;
siehe auch [[Quarzoszillator]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
* [http://www.s-t-e.de/index.html?http%3A//www.s-t-e.de/content/Tables/Tables_06.html Das Quarz-Glossar]&lt;br /&gt;
* [http://www.qsl.net/dk1ag/buch.html Das Grosse Quarzkochbuch]&lt;br /&gt;
* [http://www.wikipedia.de Wikipedia]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Anmerkung ==&lt;br /&gt;
''Der Autor möchte hier weder die an anderen Stellen zu findenden Formelsammlungen wiedergeben, noch mit diesem Artikel ein Fachbuch ersetzten. Einzig die Grundlagen, die (aus eigener Erfahrung) für einen Hobby-Bastler von Interesse sind, sollen hier dargestellt werden.''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Autor ==&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Williwilli|Williwilli]] 10:45, 15. Aug 2008 (CET)&lt;br /&gt;
&lt;br /&gt;
 [[Kategorie:Grundlagen]]&lt;br /&gt;
 [[Kategorie:Elektronik]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Transistor&amp;diff=17436</id>
		<title>Transistor</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Transistor&amp;diff=17436"/>
				<updated>2011-05-27T17:21:24Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Grundschaltungen ( NPN-Transitor) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein Transistor ist ein elektronisches Halbleiterbauelement. Dieser wird zum Schalten und Verstärken benutzt. Die Bezeichnung ''Transistor'' ist ein Kurzwort, das sich vom englischen ''Transfer Varistor'' ableitet und den Transistor als bei bipolaren durch Strom bzw. bei FETs durch Spannung steuerbaren Widerstand umschreibt. &lt;br /&gt;
&lt;br /&gt;
Transistoren werden in zwei Gruppen unterteilt:&lt;br /&gt;
* Bipolare Transitoren&lt;br /&gt;
* [[Feldeffekttransistor]]en (FETs)&lt;br /&gt;
&lt;br /&gt;
Bipolare Transistoren werden durch Stromfluss angesteuert. Die Anschlüsse des bipolaren Transistors sind ''Kollektor'', ''Basis'' und ''Emitter''. Ein kleiner Strom auf der Basis-Emitter-Strecke kann dabei einen großen Strom auf der Kollektor-Emitter-Strecke steuern. Es wird unter anderem auch zwischen NPN- und PNP-Transistoren unterschieden.&lt;br /&gt;
&lt;br /&gt;
Bei FETs (&amp;quot;Field Effect Transistor&amp;quot;)werden die Anschlüsse als Gate (engl. Tor, Gatter), Drain (engl. Abfluss), Source (engl. Quelle) bezeichnet. Der Strom auf der Drain-Source-Strecke wird hier durch die Spannung zwischen Gate und Source gesteuert. Die Steuerung mit Gleichspannung erfolgt stromlos. Bei Steuerung mit Wechselspannung wird ein Strom fürs Umladen der Gate-Kapazität benötigt.&lt;br /&gt;
&lt;br /&gt;
Die FET's kann man auf  j-FET's (&amp;quot;junction FET&amp;quot;) und MOSFET's (&amp;quot;Metall Oxide Semiconductor FET&amp;quot;) unterteilen, wobei Gate (G) vom Kanal (D-S Strecke) isolliert ist.&lt;br /&gt;
&lt;br /&gt;
{{Ausbauwunsch|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Funktionsprinzip ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:Ib-Kennlinie, BC547.gif|thumb|Spannungs-Strom-Kennlinie der Basis-Emitter-Strecke]]&lt;br /&gt;
Gehen wir zunächst von einem NPN-Transistor aus, dessen Emitter auf Masse liegt. Durch ihn können zwei Ströme fließen: Der Basis-Emitter-Strom (Kurz: I&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt;) und der Collector-Emitter-Strom (Kurz: I&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;). Der Basisstrom I&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt; ist der Steuerstrom. Die Spannungs-Strom-Kennlinie der Basis-Emitter-Strecke ähnelt einer Diodenkennlinie: Bis ca. 0,6V fließt kaum Strom, danach steigt die Stromstärke schnell an (siehe Grafik). Diese Kennlinie ist auch noch temperaturabhängig, bei höheren Temperaturen kann ein höherer Strom fließen. Wenn nun eine Schwellenspannung (= ab dieser Spannung lässt die Basis Strom fließen, hier gehen wir von Silizium aus; bei Germanium würde die Schwellenspannung schon bei 0,35V sein) von 0,7V an die Basis anlegt wird, würde zuerst nur ein kleiner Strom fließen. Mit der Zeit würde sich der Transistor erwärmen, wodurch ein höherer Strom fließen kann. Dadurch wird jedoch auch wieder die Wärmeabgabe größer, ein Teufelskreis entsteht und irgendwann brennt der Transistor durch. Um das zu verhindern, benutzt man, je nachdem wie groß die Last ist, die am Transistor angeschlossen ist, Basis-Vorwiderstände in der Größenordnung von 220 Ohm bis 100 kOhm. Diese werden zwischen die Ansteuerung und die Basis des Transistors geschaltet und begrenzen den Strom, der durch die Basis fließen kann.&lt;br /&gt;
[[Bild:Ic-Kennlinie, BC547.gif|thumb|Spannungs-Strom-Kennlinine der Collector-Emitter-Strecke]]&lt;br /&gt;
Die Collector-Emitter-Strecke des Transistors hat eine Kennlinie, die zuerst in etwa linear ansteigt und dann bei einer bestimmten Stromstärke in eine fast waagrechte Gerade übergeht (siehe Grafik).&lt;br /&gt;
Bei welcher Stromstärke die Gerade abknickt, hängt von dem Strom ab, der durch die Basis-Emitter-Strecke fließt. Je höher dieser ist, desto später knickt die Gerade ab, und desto größere Lasten kann man schalten. In einem begrenzten Bereich ändert sich der Basisstrom linear zum Collectorstrom. Die Basis-Emitter-Stromstärken betragen in der Grafik von unten nach oben 0mA, 5mA, 10mA, 15mA und 20mA.&lt;br /&gt;
Das Verhältnis aus dem Strom, der auf der Collector-Emitter-Strecke fließen kann, und dem Strom, der dazu als Steuerstrom benötigt wird, nennt man Verstärkungsfaktor. Der Verstärkungsfaktor, der bei einem Transistor angegeben ist, ist jedoch eine rein theoretische Größe. Die Werte, die im Datenblatt angegeben sind, beziehen sich meistens auf eine Collector-Emitter-Spannung von 5V, bei höheren Lastströmen sinkt der Verstärkungsfaktor weiter. Für Schaltanwendungen sollte man daher von etwa der halben Stromverstärkung ausgehen, damit die Emitter-Collector-Spannung sicher klein bleibt.  &lt;br /&gt;
Wie groß man I&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt; wählen muss, probiert man in einer Schaltungssimulation aus, oder berechnet es näherungsweise.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Bei einem PNP-Transistor sind im Grunde alle Spannungen umgedreht. Der Emitter zeigt nicht zur Masse, sondern zur positiven Versorgung (Vcc, z.B. 5 V). Die Basis muss auf einer niedrigeren Spannung liegen, beispielsweise 4,3V, damit der Transistor durchschaltet. Der Strom fließt aber weiterhin von + nach - (technische Stromrichtung angenommen)&lt;br /&gt;
&lt;br /&gt;
== Schaltsymbol und Anschlussbelegung ==&lt;br /&gt;
[[Bild:Transistor.JPG|thumb|300px|{{FarbigerRahmen|&lt;br /&gt;
'''Warnung:'''&lt;br /&gt;
Es gibt ebenso Transistoren im TO-92 Gehäuse, deren Basis an der Seite liegt. &lt;br /&gt;
Bevor du einen Transistor verwendest, solltest du auf jeden Falls sein Datenblatt gelesen haben&lt;br /&gt;
bzw. dir sicher sein, wo sich welcher Anschluss befindet!&lt;br /&gt;
}}]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:Schaltsymbol NPN.png|thumb|250px|left|Schaltsymbol npn-Transistor. Der Pfeil zeigt von der Basis (p) zum Emitter (n)]] &lt;br /&gt;
&amp;lt;br style=&amp;quot;clear:left&amp;quot;/&amp;gt;&lt;br /&gt;
[[Bild:Schaltsymbol PNP.png|thumb|250px|left|Schaltsymbol pnp-Transistor. Der Pfeil zeigt vom Emitter (p) zur Basis (n)]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear:both&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Grundschaltungen (Als Beispiel: NPN-Transitor) ==&lt;br /&gt;
Die Grundschaltung ist immer bezuglich der Ein- und Asgangsignalen definiert und kann für DC und AC unterschiedlich sein. Bei AC Schaltungen entscheidet die Elektrode, die für AC Signale mit GND (0 V) kurzgeschlossen ist.&lt;br /&gt;
=== Emitterschaltung ===&lt;br /&gt;
[[Bild:Emitterschaltung.gif|thumb|Grundschaltung der Emitterschaltung]]&lt;br /&gt;
(1) Die Emitterschaltung besteht hauptsächlich aus dem Transistor, dem Kollektorwiderstand und dem Basis-Vorwiderstand. Ist an der Basis eine Spannung von unter 0,6V anlegt, ist der Transistor nicht leitend, also hochomig. Weil der hochomige Transistor einen höheren Widerstand als der Kollektorwiderstand aufweist fällt bei ihm die größte Spannung ab. Der Ausgang der Schaltung wird durch den Widerstand auf die positive Versorgungsspannung (Vcc) &amp;quot;gezogen&amp;quot;. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
(2) Wenn man nun eine Spannung am Eingang anlegt, die größer als ca. 0,6V ist, fließt ein Strom durch die Basis des Transistors. Der Transistor wird leitend und zieht den Ausgang der Schaltung auf 0V (GND).&amp;lt;br&amp;gt;&lt;br /&gt;
Durch die Offsetspannung von 0,6V ist diese Schaltung nicht zum linearen Verstärken von Signalen geeignet. Die Schaltung kann nur als Schalter genutzt werden, sei es um die Flanken auf einem Signal zu verbessern (steiler zu machen) oder um Lasten zu schalten.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
In ersterem Fall muss man beachten, dass die Emitterschaltung das Signal invertiert, d.h. bei 0V am Eingang liegen 5V am Ausgang an und umgekehrt.&lt;br /&gt;
In letzterem Fall wird die Last (beispielsweise eine Glühbirne) statt Rc angeschlossen. Sobald man nun eine Spannung an die Basis anlegt, wird der Transistor leitend und es kann ein Strom durch die Last fließen, die Lampe leuchtet.&lt;br /&gt;
Bei großen Lasten benötigt der Transistor einen entsprechend hohen Basisstrom, der durch den Basis-Vorwiderstand eingestellt wird.&lt;br /&gt;
&lt;br /&gt;
==== Erweiterte Emitterschaltung ====&lt;br /&gt;
[[Bild:Emitterschaltung, erweitert.gif|thumb|Emitterschaltung zum linearen Verstärken von Wechselspannungen]]&lt;br /&gt;
Wenn man die Emitterschaltung zum linearen Verstärken eines Signals nutzen will, muss man sie noch ein wenig erweitern. An die Basis wird zusätzlich ein Pullup-Widerstand angeschlossen. Dieser sorgt dafür, dass der Transistor &amp;quot;vorgespannt&amp;quot; wird. Der Widerstand wird dabei gerade so groß gewählt, dass der Ausgang möglichst genau zwischen GND und der Versorgungsspannung liegt.&amp;lt;br&amp;gt;&lt;br /&gt;
Hinter den Ausgang und vor den Eingang müssen zusätzlich so genannte Koppelkondensatoren geschaltet werden. Diese sorgen am Eingang dafür, dass die angelegte Eingangsspannung die Vorspannung nicht zerstört und am Ausgang dafür, dass kein Gleichstrom durch die Last fließen kann. Dies ist vor allem bei Lautsprechern wichtig.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Emitterschaltung kann in dieser Form sowohl negative als auch positive Wechselspannungen verstärken. Für Gleichspannungen ist sie nicht mehr geeignet, da die Koppelkondensatoren diesen sperren.&amp;lt;br&amp;gt;&lt;br /&gt;
Wenn man eine Wechselspannung anlegt, fließt zusätzlich zu dem Vorspannstrom ein Eingangsstrom, der den Transistor entweder leitender (positive Halbwelle) oder weniger leitend (negative Halbwelle) macht.&amp;lt;br&amp;gt;&lt;br /&gt;
In ersterem Fall wird der Kollektor des Transistors durch selbigen auf eine negativere Spannung gezogen. Durch den Koppelkondensator am Ausgang fließt dann ein Strom in Richtung des Kollektors, bis der Kondensator durch diesen weit genug aufgeladen ist.&amp;lt;br&amp;gt;&lt;br /&gt;
im anderen Fall wird der Transistor weniger leitend, der Kollektor des Transistors wird dann durch den Widerstand Rc auf eine positivere Spannung gezogen. Folglich fließt durch den Koppelkondensator am Ausgang ein Strom in Richtung der Last, allerdings auch hier nur solange der Kondensator nicht vollständig geladen ist.&lt;br /&gt;
&lt;br /&gt;
=== Kollektorschaltung ===&lt;br /&gt;
[[Bild:Kollektorschaltung.gif|thumb|Kollektorschaltung mit NPN-Transistor]]&lt;br /&gt;
Für eine Kollektorschaltung werden zunächst nur ein Transistor und ein Widerstand benötigt.&amp;lt;br&amp;gt;&lt;br /&gt;
Ohne Eingangsspannung leitet der Transistor nicht, der Ausgang liegt also auf 0V.&amp;lt;br&amp;gt;&lt;br /&gt;
Sobald man am Eingang eine Spannung anlegt, wird der Transistor jedoch leitend, die Ausgangsspannung wird größer. Gleichzeitig wird dadurch die Basis-Emitterspannung kleiner. Der Ausgang erreicht also maximal etwa die Eingangsspannung abzüglich der 0,7 Volt, die benötigt werden, damit auf der Basis-Emitterstrecke ein Strom fließen kann. Die Spannungsverstärkung ist folglich etwas kleiner als 1. Im Gegenzug besitzt die Kollektorschaltung eine sehr hohe Stromverstärkung und dadurch auch einen sehr hohen Eingangswiderstand. Die Kollektorschaltung wird auch als Emitterfolger bezeichnet.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei dieser Schaltung kann auf den Basis-Vorwiderstand verzichtet werden, solange man am Eingang keine Spannung anlegt, die größer ist als die Versorgungsspannung. Der Strom durch die Basis reguliert sich durch die variable Emitterspannung selbst. Allerdings kann ein Basis-Vorwiderstand auch als Kurzschlussschutz dienen, da bei einem begrenzten Basisstrom auch der Kollektor-Emitterstrom begrenzt ist.&lt;br /&gt;
&lt;br /&gt;
=== Basisschaltung ===&lt;br /&gt;
[[Bild:Pegelwandler.png|thumb|Pegelwandler für 3 V auf 5 V Logicpegel, mit NPN Transistor in Basisschaltung.]]&lt;br /&gt;
In der Basisschaltung wird die Basis fest auf eine mittlere Spannung gelegt. Der Strom am Emitter dient als Eingang, der Strom am Kollektor als Ausgang. Wenn man den kleinen Basisstrom vernachlässigt, sind der Emitter- und Kollektorstrom gleich groß. Wenn der Widerstand (bzw. die Impedanz) an der Emitterseite niedriger als an der Kollektorseite ist, ergibt sich eine Spannungsverstärkung. Die Basisschaltung wird hauptsächlich in HF-Schaltungen benutzt. &lt;br /&gt;
&lt;br /&gt;
Eine weitere Anwedung sind Pegelwandler. Die Schaltung im Bild rechts dient dazu, ein Digitalsignal von einem IC mit 2-3 V Versorgung auf 5 V zu Verstärken.  Wenn am Eingang mehr als etwa 1 V anliegen, sperrt der Transistor, und am Ausgang liegt die Spannung über den 1 K Widerstand. Wenn der Eingang auf GND Potential ist, ist der Transistor durchgeschaltet und der Ausgang liegt fast auf GND Potential. Der Basisstrom wird durch den 22 K Widerstand auf rund 0,2 mA begrenzt. Die Schaltung ist keine reine Basisschaltung, denn die Spannung an der Baisis ändert sich hier ein wenig.&lt;br /&gt;
&lt;br /&gt;
=== Darlingtonschaltung ===&lt;br /&gt;
[[Bild:Darlington.png|thumb|Darlingtonschaltung (NPN)]]&lt;br /&gt;
Wenn die Stromverstärkung eines einzelnen Transistors nicht ausreicht, können zwei Transistoren so zusammengeschaltet werden, dass der Emitter des ersten Transistors an die Basis des zweiten Transistors geht. Die Collectoren sind miteinander verbunden. Diese Schaltung verhält sich dann ganz ähnlich wie ein Transistor mit einer Stromverstärkung, die dem Produkt der beiden Stromverstärkungen entspricht. In einem Gehäuse zusammengefasst bezeichnet man diese Schaltung als Darlingtontransistor. Der im Bild gezeigte Widerstand kann auch weggelassen werden. Er macht die Schaltung schneller und reduziert den Leckstrom.&lt;br /&gt;
&lt;br /&gt;
=== Verstärkung mit Gegenkopplung ===&lt;br /&gt;
==== Spannungsgegenkopplung ====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Spannungsgegenkopplung.png|thumb|Verstärker mit Spannungsgegenkopplung]]&lt;br /&gt;
&lt;br /&gt;
Die Verstärkung mit der Emitterschaltung ist von den Eigenschaften (besonders Verstärkungsfaktor) des verwendeten Transistors abhängig und damit auch temperaturabhängig. Außerdem ist die Verstärkung nicht besonders linear.&lt;br /&gt;
Die Schaltung im Bild zeigt einen Weg eine stabilere Verstärkung zu erzeugen. Über den Widerstand R2 wirkt die Ausgangsspannung der Eingangsspannung entgegen. &lt;br /&gt;
Diese Schaltungprinzip wird daher Spannungsgegenkopplung genannt.&lt;br /&gt;
Die Verstärkung ist in diesem Fall auf -R2/R3 = -5 fach festgelegt. Damit die Gegenkopplung wirken kann, muss die Verstärkung ohne die Gegenkopplung wesentlich höher sein, als sie durch die Widerstände eingestellt wird. Durch die Gegenkopplung reduziert sich die Verstärkung zugunsten einer besseren Linearität und Stabilität. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Stromgegenkopplung ====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Stromgegenkopplung.png|thumb|Verstärker mit Stromgegenkopplung]]&lt;br /&gt;
&lt;br /&gt;
Eine andere Form der Gegenkopplung zeigt das Bild rechts. Hier ist die Rückkopplung nicht so klar zu sehen, denn die Rückkopplung wirkt nicht auf die Basis, sondern auf den Emitter. Der Kollektorstrom hängt vom Basistrom ab und damit von der Spannung zwischen Basis und Emitter. Eine höhere Spannung am Emitter ist daher gleichbedeutend mit einer niedrigeren Spannung an der Basis und weniger Strom. Der Strom durch dem Kollektor fleißt auch durch den Widerstand am Emitter, erhöht dort die Spannung und wirkt so einem höheren Strom entgegen. Man nennt diese Schaltung daher auch Stromgegenkopplung. Auch hier reduziert sich die Verstärkung auf etwa -R2/R3.&lt;br /&gt;
&lt;br /&gt;
=== Wie erkenne ich, um welche Grundschaltung es sich handelt? ===&lt;br /&gt;
Einfache Vorgehensweise: Der Anschluss des Transistors, der weder als Eingang noch als Ausgang dient, gibt der Schaltung ihren Namen.&lt;br /&gt;
Bsp: Eingang Basis, Ausgang Kollektor. Dann handelt es sich um eine Emitterschaltung, weil der Emitter weder Eingang noch Ausgang ist.&lt;br /&gt;
&lt;br /&gt;
=== Logische Interpretation der Schaltungen ===&lt;br /&gt;
====Die NOT-Verknüpfung====&lt;br /&gt;
&lt;br /&gt;
[[Bild:NOT Gatter.JPG]]&lt;br /&gt;
&lt;br /&gt;
Diese einfache Schaltung, bestehend aus einem NPN-Transistor und zwei Widerständen, invertiert das Eingangssignal, sodass aus beispielsweise +5V (oder logisch 1) 0V (oder logisch 0) erzeugt werden.&lt;br /&gt;
Die daraus resultierende Wertetabelle sieht folgendermaßen aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align = &amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 | '''Eingang'''&lt;br /&gt;
 | '''Ausgang'''&lt;br /&gt;
 |-&lt;br /&gt;
 | 0V&lt;br /&gt;
 | +5V&lt;br /&gt;
 |-&lt;br /&gt;
 | +5V&lt;br /&gt;
 | 0V&lt;br /&gt;
 |}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Wenn also an der Transistorbasis +5V angelegt werden (+0,7V reichen meistens auch schon), dann schaltet der Transistor durch und am Ausgang liegen 0V an. Der Strom, der nun durch den Transistor fließt, wird durch den Widerstand R&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; begrenzt. Wird dieser Widerstand weggelassen, dann wird durch den entstehenden Kurzschluss der Transistor unweigerlich zerstört.&lt;br /&gt;
Legt man nun am Eingang 0V an, so sperrt der Transistor und am Ausgang liegen +5V an. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Basisstrom wird durch den Widerstand R&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; bestimmt. Ein kleiner Widerstand beschleunigt die Schaltgeschwindigkeit des Transistors, ein großer ermöglicht die Ansteuerung auch mit kleinen Strömen.&lt;br /&gt;
&lt;br /&gt;
Baut man die obere Schaltung doppelt auf und verbindet beide Ausgänge miteinander, erhält man ein NOR-Gatter.&lt;br /&gt;
&lt;br /&gt;
====Die NAND Verknüpfung====&lt;br /&gt;
&lt;br /&gt;
[[Bild:NAND_Gatter.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die NAND ('''N'''ot'''AND''', d.h. die invertierte Form einer AND Verknüpfung) Verknüpfung besteht aus zwei Transistoren und damit auch zwei Eingängen. Es gibt auch NAND Verknüpfungen mit mehr Transistoren und folglich auch mehr Eingängen, diese sind im Aufbau aber sehr ähnlich zu der vorgestellten Grund-NAND Verknüpfung.&lt;br /&gt;
Schauen wir uns zunächst die Wertetabelle an:&lt;br /&gt;
&amp;lt;div align = &amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 | '''Eingang 1 (E1)'''&lt;br /&gt;
 | '''Eingang 2 (E2)'''&lt;br /&gt;
 | '''Ausgang (A1)'''&lt;br /&gt;
 |-&lt;br /&gt;
 |   0V&lt;br /&gt;
 |   0V&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |-&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |   0V&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |-&lt;br /&gt;
 |   0V&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |-&lt;br /&gt;
 | +5V&lt;br /&gt;
 | +5V&lt;br /&gt;
 | 0V&lt;br /&gt;
 |}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie kommt es nun zu dieser Werte- oder auch Wahrheitstabelle?&lt;br /&gt;
&lt;br /&gt;
Wenn an den beiden Eingängen 0V anliegen, dann schaltet keiner der beiden Transistoren durch und der Ausgang ist über den Widerstand R&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt; mit +5V verbunden.&lt;br /&gt;
Wechselt nun einer der beiden Eingänge auf 1, dann schaltet auch nur einer der beiden Transistoren durch und am Ausgang liegen immer noch +5V an. Werden nun aber beide Eingänge mit +5V verbunden, dann schalten beide Transistoren durch und der Ausgang ist leitend mit Masse verbunden.&lt;br /&gt;
&lt;br /&gt;
Die Widerstände (R&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;, R&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;, R&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;) haben die gleiche Funktion wie auch in der NOT Verknüpfung.&lt;br /&gt;
&lt;br /&gt;
== Transistor-Kennwerte ==&lt;br /&gt;
Die Transistorkennwerte sind grundsätzlich in Grenzdaten und Kenndaten unterteilt. Grenzwerte dürfen auf keinen Fall überschritten werden, da eine Zerstörung des Transistors möglich ist. Eigenschaften eines Transistors werden als Kenndaten angegeben, die das Verhalten in bestimmten Arbeitspunkten kennzeichnen.&lt;br /&gt;
&lt;br /&gt;
===Grenzwerte für Sperrschichttemperatur===&lt;br /&gt;
Durch die Verlustleistung bei Dauerbetrieb entsteht in der Sperrschicht Wärme, durch die sich die Sperrschichttemperatur erhöht. Die Sperrschichttemperatur '''T&amp;lt;sub&amp;gt;J&amp;lt;/sub&amp;gt; ''' , darf bestimmte Werte nicht überschreiten, da sich sonst die Eigenschaften des Transistors stark verändern würden (z.B. sehr hoher Leckstrom), was oft eine Zerstörung zur Folge hat. Die maximale Temperatur hängt vom Halbleitermaterial ab.&lt;br /&gt;
&lt;br /&gt;
'''T&amp;lt;sub&amp;gt;J&amp;lt;/sub&amp;gt; ''' : 90°C Germaniumtransistoren&lt;br /&gt;
&lt;br /&gt;
'''T&amp;lt;sub&amp;gt;J&amp;lt;/sub&amp;gt; ''' : 150 - 200°C Siliziumtransistoren&lt;br /&gt;
&lt;br /&gt;
===Zulässiger Arbeitsbereich===&lt;br /&gt;
In Transistorschaltungen dürfen bestimmte Grenzwerte nicht überschritten werden. Der zulässige Arbeitsbereich einer Transistorschaltung wird somit durch den Kollektorstrom '''I&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; ''', durch die Kollektor - Emitterspannung '''U&amp;lt;sub&amp;gt;CE&amp;lt;/sub&amp;gt; ''' und durch die Verlustleistung '''P&amp;lt;sub&amp;gt;tot&amp;lt;/sub&amp;gt; ''' begrenzt. Wird der Transistor außerhalb des erlaubten Arbeitsbereiches betrieben wird der Transistor zerstört.  &lt;br /&gt;
Die zulässige Verlustleistung wird bei kleinen Transistoren oft für 25°C Umgebungstemperatur angegeben. Bei Leistungstransistoren wird oft 25°C Gehäusetemperatur vorausgesetzt. Bei höheren Temperaturen oder schlechterer Kühlung, was fast immer der Fall ist, reduziert sich die zulässige Verlustleistung.  In den Datenblättern findet man dazu Zahlenwerte und teilweise Diagramme zur zulässigen Verlustleistung als Funktion der Umgebungstemperatur. Je nach Wärmewiderstand '''R&amp;lt;sub&amp;gt;Th&amp;lt;/sub&amp;gt; ''' eines ggf. vorhandenen Kühlkörpers ergeben sich unterschiedliche Kurven.&lt;br /&gt;
&lt;br /&gt;
===Kenndaten===&lt;br /&gt;
Von den Kenndaten ist im wesentlichen der Stromverstärkungsfaktor ('''h&amp;lt;sub&amp;gt;FE&amp;lt;/sub&amp;gt; ''') wichtig. Für Schaltanwendungen interessiert noch die Kollektor-Emitter-Sättigungsspannung. Die anderen Kenndaten sind im wesentlichen für fortgeschrittene Schaltungen wichtig.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Autor: ZwieBack - Wiki Konvertierung Frank''&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Feldeffekttransistor|FET]]&lt;br /&gt;
* [[Kleinsignalverstärker]]&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
* [http://www.nano.physik.uni-muenchen.de/elektronik/nav/k5t2.html Grundlagen Transistorschaltungen] Anm.: Seite existiert nicht mehr&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/Transistor Mikrocontroller.net/Transistor]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Transistor Wikipedia/Transistor]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Transistor&amp;diff=17435</id>
		<title>Transistor</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Transistor&amp;diff=17435"/>
				<updated>2011-05-27T17:08:43Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein Transistor ist ein elektronisches Halbleiterbauelement. Dieser wird zum Schalten und Verstärken benutzt. Die Bezeichnung ''Transistor'' ist ein Kurzwort, das sich vom englischen ''Transfer Varistor'' ableitet und den Transistor als bei bipolaren durch Strom bzw. bei FETs durch Spannung steuerbaren Widerstand umschreibt. &lt;br /&gt;
&lt;br /&gt;
Transistoren werden in zwei Gruppen unterteilt:&lt;br /&gt;
* Bipolare Transitoren&lt;br /&gt;
* [[Feldeffekttransistor]]en (FETs)&lt;br /&gt;
&lt;br /&gt;
Bipolare Transistoren werden durch Stromfluss angesteuert. Die Anschlüsse des bipolaren Transistors sind ''Kollektor'', ''Basis'' und ''Emitter''. Ein kleiner Strom auf der Basis-Emitter-Strecke kann dabei einen großen Strom auf der Kollektor-Emitter-Strecke steuern. Es wird unter anderem auch zwischen NPN- und PNP-Transistoren unterschieden.&lt;br /&gt;
&lt;br /&gt;
Bei FETs (&amp;quot;Field Effect Transistor&amp;quot;)werden die Anschlüsse als Gate (engl. Tor, Gatter), Drain (engl. Abfluss), Source (engl. Quelle) bezeichnet. Der Strom auf der Drain-Source-Strecke wird hier durch die Spannung zwischen Gate und Source gesteuert. Die Steuerung mit Gleichspannung erfolgt stromlos. Bei Steuerung mit Wechselspannung wird ein Strom fürs Umladen der Gate-Kapazität benötigt.&lt;br /&gt;
&lt;br /&gt;
Die FET's kann man auf  j-FET's (&amp;quot;junction FET&amp;quot;) und MOSFET's (&amp;quot;Metall Oxide Semiconductor FET&amp;quot;) unterteilen, wobei Gate (G) vom Kanal (D-S Strecke) isolliert ist.&lt;br /&gt;
&lt;br /&gt;
{{Ausbauwunsch|&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Funktionsprinzip ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:Ib-Kennlinie, BC547.gif|thumb|Spannungs-Strom-Kennlinie der Basis-Emitter-Strecke]]&lt;br /&gt;
Gehen wir zunächst von einem NPN-Transistor aus, dessen Emitter auf Masse liegt. Durch ihn können zwei Ströme fließen: Der Basis-Emitter-Strom (Kurz: I&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt;) und der Collector-Emitter-Strom (Kurz: I&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt;). Der Basisstrom I&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt; ist der Steuerstrom. Die Spannungs-Strom-Kennlinie der Basis-Emitter-Strecke ähnelt einer Diodenkennlinie: Bis ca. 0,6V fließt kaum Strom, danach steigt die Stromstärke schnell an (siehe Grafik). Diese Kennlinie ist auch noch temperaturabhängig, bei höheren Temperaturen kann ein höherer Strom fließen. Wenn nun eine Schwellenspannung (= ab dieser Spannung lässt die Basis Strom fließen, hier gehen wir von Silizium aus; bei Germanium würde die Schwellenspannung schon bei 0,35V sein) von 0,7V an die Basis anlegt wird, würde zuerst nur ein kleiner Strom fließen. Mit der Zeit würde sich der Transistor erwärmen, wodurch ein höherer Strom fließen kann. Dadurch wird jedoch auch wieder die Wärmeabgabe größer, ein Teufelskreis entsteht und irgendwann brennt der Transistor durch. Um das zu verhindern, benutzt man, je nachdem wie groß die Last ist, die am Transistor angeschlossen ist, Basis-Vorwiderstände in der Größenordnung von 220 Ohm bis 100 kOhm. Diese werden zwischen die Ansteuerung und die Basis des Transistors geschaltet und begrenzen den Strom, der durch die Basis fließen kann.&lt;br /&gt;
[[Bild:Ic-Kennlinie, BC547.gif|thumb|Spannungs-Strom-Kennlinine der Collector-Emitter-Strecke]]&lt;br /&gt;
Die Collector-Emitter-Strecke des Transistors hat eine Kennlinie, die zuerst in etwa linear ansteigt und dann bei einer bestimmten Stromstärke in eine fast waagrechte Gerade übergeht (siehe Grafik).&lt;br /&gt;
Bei welcher Stromstärke die Gerade abknickt, hängt von dem Strom ab, der durch die Basis-Emitter-Strecke fließt. Je höher dieser ist, desto später knickt die Gerade ab, und desto größere Lasten kann man schalten. In einem begrenzten Bereich ändert sich der Basisstrom linear zum Collectorstrom. Die Basis-Emitter-Stromstärken betragen in der Grafik von unten nach oben 0mA, 5mA, 10mA, 15mA und 20mA.&lt;br /&gt;
Das Verhältnis aus dem Strom, der auf der Collector-Emitter-Strecke fließen kann, und dem Strom, der dazu als Steuerstrom benötigt wird, nennt man Verstärkungsfaktor. Der Verstärkungsfaktor, der bei einem Transistor angegeben ist, ist jedoch eine rein theoretische Größe. Die Werte, die im Datenblatt angegeben sind, beziehen sich meistens auf eine Collector-Emitter-Spannung von 5V, bei höheren Lastströmen sinkt der Verstärkungsfaktor weiter. Für Schaltanwendungen sollte man daher von etwa der halben Stromverstärkung ausgehen, damit die Emitter-Collector-Spannung sicher klein bleibt.  &lt;br /&gt;
Wie groß man I&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt; wählen muss, probiert man in einer Schaltungssimulation aus, oder berechnet es näherungsweise.&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Bei einem PNP-Transistor sind im Grunde alle Spannungen umgedreht. Der Emitter zeigt nicht zur Masse, sondern zur positiven Versorgung (Vcc, z.B. 5 V). Die Basis muss auf einer niedrigeren Spannung liegen, beispielsweise 4,3V, damit der Transistor durchschaltet. Der Strom fließt aber weiterhin von + nach - (technische Stromrichtung angenommen)&lt;br /&gt;
&lt;br /&gt;
== Schaltsymbol und Anschlussbelegung ==&lt;br /&gt;
[[Bild:Transistor.JPG|thumb|300px|{{FarbigerRahmen|&lt;br /&gt;
'''Warnung:'''&lt;br /&gt;
Es gibt ebenso Transistoren im TO-92 Gehäuse, deren Basis an der Seite liegt. &lt;br /&gt;
Bevor du einen Transistor verwendest, solltest du auf jeden Falls sein Datenblatt gelesen haben&lt;br /&gt;
bzw. dir sicher sein, wo sich welcher Anschluss befindet!&lt;br /&gt;
}}]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:Schaltsymbol NPN.png|thumb|250px|left|Schaltsymbol npn-Transistor. Der Pfeil zeigt von der Basis (p) zum Emitter (n)]] &lt;br /&gt;
&amp;lt;br style=&amp;quot;clear:left&amp;quot;/&amp;gt;&lt;br /&gt;
[[Bild:Schaltsymbol PNP.png|thumb|250px|left|Schaltsymbol pnp-Transistor. Der Pfeil zeigt vom Emitter (p) zur Basis (n)]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br style=&amp;quot;clear:both&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Grundschaltungen ( NPN-Transitor) ==&lt;br /&gt;
=== Emitterschaltung ===&lt;br /&gt;
[[Bild:Emitterschaltung.gif|thumb|Grundschaltung der Emitterschaltung]]&lt;br /&gt;
(1) Die Emitterschaltung besteht hauptsächlich aus dem Transistor, dem Kollektorwiderstand und dem Basis-Vorwiderstand. Ist an der Basis eine Spannung von unter 0,6V anlegt, ist der Transistor nicht leitend, also hochomig. Weil der hochomige Transistor einen höheren Widerstand als der Kollektorwiderstand aufweist fällt bei ihm die größte Spannung ab. Der Ausgang der Schaltung wird durch den Widerstand auf die positive Versorgungsspannung (Vcc) &amp;quot;gezogen&amp;quot;. &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
(2) Wenn man nun eine Spannung am Eingang anlegt, die größer als ca. 0,6V ist, fließt ein Strom durch die Basis des Transistors. Der Transistor wird leitend und zieht den Ausgang der Schaltung auf 0V (GND).&amp;lt;br&amp;gt;&lt;br /&gt;
Durch die Offsetspannung von 0,6V ist diese Schaltung nicht zum linearen Verstärken von Signalen geeignet. Die Schaltung kann nur als Schalter genutzt werden, sei es um die Flanken auf einem Signal zu verbessern (steiler zu machen) oder um Lasten zu schalten.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
In ersterem Fall muss man beachten, dass die Emitterschaltung das Signal invertiert, d.h. bei 0V am Eingang liegen 5V am Ausgang an und umgekehrt.&lt;br /&gt;
In letzterem Fall wird die Last (beispielsweise eine Glühbirne) statt Rc angeschlossen. Sobald man nun eine Spannung an die Basis anlegt, wird der Transistor leitend und es kann ein Strom durch die Last fließen, die Lampe leuchtet.&lt;br /&gt;
Bei großen Lasten benötigt der Transistor einen entsprechend hohen Basisstrom, der durch den Basis-Vorwiderstand eingestellt wird.&lt;br /&gt;
&lt;br /&gt;
==== Erweiterte Emitterschaltung ====&lt;br /&gt;
[[Bild:Emitterschaltung, erweitert.gif|thumb|Emitterschaltung zum linearen Verstärken von Wechselspannungen]]&lt;br /&gt;
Wenn man die Emitterschaltung zum linearen Verstärken eines Signals nutzen will, muss man sie noch ein wenig erweitern. An die Basis wird zusätzlich ein Pullup-Widerstand angeschlossen. Dieser sorgt dafür, dass der Transistor &amp;quot;vorgespannt&amp;quot; wird. Der Widerstand wird dabei gerade so groß gewählt, dass der Ausgang möglichst genau zwischen GND und der Versorgungsspannung liegt.&amp;lt;br&amp;gt;&lt;br /&gt;
Hinter den Ausgang und vor den Eingang müssen zusätzlich so genannte Koppelkondensatoren geschaltet werden. Diese sorgen am Eingang dafür, dass die angelegte Eingangsspannung die Vorspannung nicht zerstört und am Ausgang dafür, dass kein Gleichstrom durch die Last fließen kann. Dies ist vor allem bei Lautsprechern wichtig.&amp;lt;br&amp;gt;&lt;br /&gt;
Die Emitterschaltung kann in dieser Form sowohl negative als auch positive Wechselspannungen verstärken. Für Gleichspannungen ist sie nicht mehr geeignet, da die Koppelkondensatoren diesen sperren.&amp;lt;br&amp;gt;&lt;br /&gt;
Wenn man eine Wechselspannung anlegt, fließt zusätzlich zu dem Vorspannstrom ein Eingangsstrom, der den Transistor entweder leitender (positive Halbwelle) oder weniger leitend (negative Halbwelle) macht.&amp;lt;br&amp;gt;&lt;br /&gt;
In ersterem Fall wird der Kollektor des Transistors durch selbigen auf eine negativere Spannung gezogen. Durch den Koppelkondensator am Ausgang fließt dann ein Strom in Richtung des Kollektors, bis der Kondensator durch diesen weit genug aufgeladen ist.&amp;lt;br&amp;gt;&lt;br /&gt;
im anderen Fall wird der Transistor weniger leitend, der Kollektor des Transistors wird dann durch den Widerstand Rc auf eine positivere Spannung gezogen. Folglich fließt durch den Koppelkondensator am Ausgang ein Strom in Richtung der Last, allerdings auch hier nur solange der Kondensator nicht vollständig geladen ist.&lt;br /&gt;
&lt;br /&gt;
=== Kollektorschaltung ===&lt;br /&gt;
[[Bild:Kollektorschaltung.gif|thumb|Kollektorschaltung mit NPN-Transistor]]&lt;br /&gt;
Für eine Kollektorschaltung werden zunächst nur ein Transistor und ein Widerstand benötigt.&amp;lt;br&amp;gt;&lt;br /&gt;
Ohne Eingangsspannung leitet der Transistor nicht, der Ausgang liegt also auf 0V.&amp;lt;br&amp;gt;&lt;br /&gt;
Sobald man am Eingang eine Spannung anlegt, wird der Transistor jedoch leitend, die Ausgangsspannung wird größer. Gleichzeitig wird dadurch die Basis-Emitterspannung kleiner. Der Ausgang erreicht also maximal etwa die Eingangsspannung abzüglich der 0,7 Volt, die benötigt werden, damit auf der Basis-Emitterstrecke ein Strom fließen kann. Die Spannungsverstärkung ist folglich etwas kleiner als 1. Im Gegenzug besitzt die Kollektorschaltung eine sehr hohe Stromverstärkung und dadurch auch einen sehr hohen Eingangswiderstand. Die Kollektorschaltung wird auch als Emitterfolger bezeichnet.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei dieser Schaltung kann auf den Basis-Vorwiderstand verzichtet werden, solange man am Eingang keine Spannung anlegt, die größer ist als die Versorgungsspannung. Der Strom durch die Basis reguliert sich durch die variable Emitterspannung selbst. Allerdings kann ein Basis-Vorwiderstand auch als Kurzschlussschutz dienen, da bei einem begrenzten Basisstrom auch der Kollektor-Emitterstrom begrenzt ist.&lt;br /&gt;
&lt;br /&gt;
=== Basisschaltung ===&lt;br /&gt;
[[Bild:Pegelwandler.png|thumb|Pegelwandler für 3 V auf 5 V Logicpegel, mit NPN Transistor in Basisschaltung.]]&lt;br /&gt;
In der Basisschaltung wird die Basis fest auf eine mittlere Spannung gelegt. Der Strom am Emitter dient als Eingang, der Strom am Kollektor als Ausgang. Wenn man den kleinen Basisstrom vernachlässigt, sind der Emitter- und Kollektorstrom gleich groß. Wenn der Widerstand (bzw. die Impedanz) an der Emitterseite niedriger als an der Kollektorseite ist, ergibt sich eine Spannungsverstärkung. Die Basisschaltung wird hauptsächlich in HF-Schaltungen benutzt. &lt;br /&gt;
&lt;br /&gt;
Eine weitere Anwedung sind Pegelwandler. Die Schaltung im Bild rechts dient dazu, ein Digitalsignal von einem IC mit 2-3 V Versorgung auf 5 V zu Verstärken.  Wenn am Eingang mehr als etwa 1 V anliegen, sperrt der Transistor, und am Ausgang liegt die Spannung über den 1 K Widerstand. Wenn der Eingang auf GND Potential ist, ist der Transistor durchgeschaltet und der Ausgang liegt fast auf GND Potential. Der Basisstrom wird durch den 22 K Widerstand auf rund 0,2 mA begrenzt. Die Schaltung ist keine reine Basisschaltung, denn die Spannung an der Baisis ändert sich hier ein wenig.&lt;br /&gt;
&lt;br /&gt;
=== Darlingtonschaltung ===&lt;br /&gt;
[[Bild:Darlington.png|thumb|Darlingtonschaltung (NPN)]]&lt;br /&gt;
Wenn die Stromverstärkung eines einzelnen Transistors nicht ausreicht, können zwei Transistoren so zusammengeschaltet werden, dass der Emitter des ersten Transistors an die Basis des zweiten Transistors geht. Die Collectoren sind miteinander verbunden. Diese Schaltung verhält sich dann ganz ähnlich wie ein Transistor mit einer Stromverstärkung, die dem Produkt der beiden Stromverstärkungen entspricht. In einem Gehäuse zusammengefasst bezeichnet man diese Schaltung als Darlingtontransistor. Der im Bild gezeigte Widerstand kann auch weggelassen werden. Er macht die Schaltung schneller und reduziert den Leckstrom.&lt;br /&gt;
&lt;br /&gt;
=== Verstärkung mit Gegenkopplung ===&lt;br /&gt;
==== Spannungsgegenkopplung ====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Spannungsgegenkopplung.png|thumb|Verstärker mit Spannungsgegenkopplung]]&lt;br /&gt;
&lt;br /&gt;
Die Verstärkung mit der Emitterschaltung ist von den Eigenschaften (besonders Verstärkungsfaktor) des verwendeten Transistors abhängig und damit auch temperaturabhängig. Außerdem ist die Verstärkung nicht besonders linear.&lt;br /&gt;
Die Schaltung im Bild zeigt einen Weg eine stabilere Verstärkung zu erzeugen. Über den Widerstand R2 wirkt die Ausgangsspannung der Eingangsspannung entgegen. &lt;br /&gt;
Diese Schaltungprinzip wird daher Spannungsgegenkopplung genannt.&lt;br /&gt;
Die Verstärkung ist in diesem Fall auf -R2/R3 = -5 fach festgelegt. Damit die Gegenkopplung wirken kann, muss die Verstärkung ohne die Gegenkopplung wesentlich höher sein, als sie durch die Widerstände eingestellt wird. Durch die Gegenkopplung reduziert sich die Verstärkung zugunsten einer besseren Linearität und Stabilität. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Stromgegenkopplung ====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Stromgegenkopplung.png|thumb|Verstärker mit Stromgegenkopplung]]&lt;br /&gt;
&lt;br /&gt;
Eine andere Form der Gegenkopplung zeigt das Bild rechts. Hier ist die Rückkopplung nicht so klar zu sehen, denn die Rückkopplung wirkt nicht auf die Basis, sondern auf den Emitter. Der Kollektorstrom hängt vom Basistrom ab und damit von der Spannung zwischen Basis und Emitter. Eine höhere Spannung am Emitter ist daher gleichbedeutend mit einer niedrigeren Spannung an der Basis und weniger Strom. Der Strom durch dem Kollektor fleißt auch durch den Widerstand am Emitter, erhöht dort die Spannung und wirkt so einem höheren Strom entgegen. Man nennt diese Schaltung daher auch Stromgegenkopplung. Auch hier reduziert sich die Verstärkung auf etwa -R2/R3.&lt;br /&gt;
&lt;br /&gt;
=== Wie erkenne ich, um welche Grundschaltung es sich handelt? ===&lt;br /&gt;
Einfache Vorgehensweise: Der Anschluss des Transistors, der weder als Eingang noch als Ausgang dient, gibt der Schaltung ihren Namen.&lt;br /&gt;
Bsp: Eingang Basis, Ausgang Kollektor. Dann handelt es sich um eine Emitterschaltung, weil der Emitter weder Eingang noch Ausgang ist.&lt;br /&gt;
&lt;br /&gt;
=== Logische Interpretation der Schaltungen ===&lt;br /&gt;
====Die NOT-Verknüpfung====&lt;br /&gt;
&lt;br /&gt;
[[Bild:NOT Gatter.JPG]]&lt;br /&gt;
&lt;br /&gt;
Diese einfache Schaltung, bestehend aus einem NPN-Transistor und zwei Widerständen, invertiert das Eingangssignal, sodass aus beispielsweise +5V (oder logisch 1) 0V (oder logisch 0) erzeugt werden.&lt;br /&gt;
Die daraus resultierende Wertetabelle sieht folgendermaßen aus:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align = &amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 | '''Eingang'''&lt;br /&gt;
 | '''Ausgang'''&lt;br /&gt;
 |-&lt;br /&gt;
 | 0V&lt;br /&gt;
 | +5V&lt;br /&gt;
 |-&lt;br /&gt;
 | +5V&lt;br /&gt;
 | 0V&lt;br /&gt;
 |}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Wenn also an der Transistorbasis +5V angelegt werden (+0,7V reichen meistens auch schon), dann schaltet der Transistor durch und am Ausgang liegen 0V an. Der Strom, der nun durch den Transistor fließt, wird durch den Widerstand R&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; begrenzt. Wird dieser Widerstand weggelassen, dann wird durch den entstehenden Kurzschluss der Transistor unweigerlich zerstört.&lt;br /&gt;
Legt man nun am Eingang 0V an, so sperrt der Transistor und am Ausgang liegen +5V an. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Basisstrom wird durch den Widerstand R&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; bestimmt. Ein kleiner Widerstand beschleunigt die Schaltgeschwindigkeit des Transistors, ein großer ermöglicht die Ansteuerung auch mit kleinen Strömen.&lt;br /&gt;
&lt;br /&gt;
Baut man die obere Schaltung doppelt auf und verbindet beide Ausgänge miteinander, erhält man ein NOR-Gatter.&lt;br /&gt;
&lt;br /&gt;
====Die NAND Verknüpfung====&lt;br /&gt;
&lt;br /&gt;
[[Bild:NAND_Gatter.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die NAND ('''N'''ot'''AND''', d.h. die invertierte Form einer AND Verknüpfung) Verknüpfung besteht aus zwei Transistoren und damit auch zwei Eingängen. Es gibt auch NAND Verknüpfungen mit mehr Transistoren und folglich auch mehr Eingängen, diese sind im Aufbau aber sehr ähnlich zu der vorgestellten Grund-NAND Verknüpfung.&lt;br /&gt;
Schauen wir uns zunächst die Wertetabelle an:&lt;br /&gt;
&amp;lt;div align = &amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 | '''Eingang 1 (E1)'''&lt;br /&gt;
 | '''Eingang 2 (E2)'''&lt;br /&gt;
 | '''Ausgang (A1)'''&lt;br /&gt;
 |-&lt;br /&gt;
 |   0V&lt;br /&gt;
 |   0V&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |-&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |   0V&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |-&lt;br /&gt;
 |   0V&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |  +5V&lt;br /&gt;
 |-&lt;br /&gt;
 | +5V&lt;br /&gt;
 | +5V&lt;br /&gt;
 | 0V&lt;br /&gt;
 |}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wie kommt es nun zu dieser Werte- oder auch Wahrheitstabelle?&lt;br /&gt;
&lt;br /&gt;
Wenn an den beiden Eingängen 0V anliegen, dann schaltet keiner der beiden Transistoren durch und der Ausgang ist über den Widerstand R&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt; mit +5V verbunden.&lt;br /&gt;
Wechselt nun einer der beiden Eingänge auf 1, dann schaltet auch nur einer der beiden Transistoren durch und am Ausgang liegen immer noch +5V an. Werden nun aber beide Eingänge mit +5V verbunden, dann schalten beide Transistoren durch und der Ausgang ist leitend mit Masse verbunden.&lt;br /&gt;
&lt;br /&gt;
Die Widerstände (R&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;, R&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;, R&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;) haben die gleiche Funktion wie auch in der NOT Verknüpfung.&lt;br /&gt;
&lt;br /&gt;
== Transistor-Kennwerte ==&lt;br /&gt;
Die Transistorkennwerte sind grundsätzlich in Grenzdaten und Kenndaten unterteilt. Grenzwerte dürfen auf keinen Fall überschritten werden, da eine Zerstörung des Transistors möglich ist. Eigenschaften eines Transistors werden als Kenndaten angegeben, die das Verhalten in bestimmten Arbeitspunkten kennzeichnen.&lt;br /&gt;
&lt;br /&gt;
===Grenzwerte für Sperrschichttemperatur===&lt;br /&gt;
Durch die Verlustleistung bei Dauerbetrieb entsteht in der Sperrschicht Wärme, durch die sich die Sperrschichttemperatur erhöht. Die Sperrschichttemperatur '''T&amp;lt;sub&amp;gt;J&amp;lt;/sub&amp;gt; ''' , darf bestimmte Werte nicht überschreiten, da sich sonst die Eigenschaften des Transistors stark verändern würden (z.B. sehr hoher Leckstrom), was oft eine Zerstörung zur Folge hat. Die maximale Temperatur hängt vom Halbleitermaterial ab.&lt;br /&gt;
&lt;br /&gt;
'''T&amp;lt;sub&amp;gt;J&amp;lt;/sub&amp;gt; ''' : 90°C Germaniumtransistoren&lt;br /&gt;
&lt;br /&gt;
'''T&amp;lt;sub&amp;gt;J&amp;lt;/sub&amp;gt; ''' : 150 - 200°C Siliziumtransistoren&lt;br /&gt;
&lt;br /&gt;
===Zulässiger Arbeitsbereich===&lt;br /&gt;
In Transistorschaltungen dürfen bestimmte Grenzwerte nicht überschritten werden. Der zulässige Arbeitsbereich einer Transistorschaltung wird somit durch den Kollektorstrom '''I&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; ''', durch die Kollektor - Emitterspannung '''U&amp;lt;sub&amp;gt;CE&amp;lt;/sub&amp;gt; ''' und durch die Verlustleistung '''P&amp;lt;sub&amp;gt;tot&amp;lt;/sub&amp;gt; ''' begrenzt. Wird der Transistor außerhalb des erlaubten Arbeitsbereiches betrieben wird der Transistor zerstört.  &lt;br /&gt;
Die zulässige Verlustleistung wird bei kleinen Transistoren oft für 25°C Umgebungstemperatur angegeben. Bei Leistungstransistoren wird oft 25°C Gehäusetemperatur vorausgesetzt. Bei höheren Temperaturen oder schlechterer Kühlung, was fast immer der Fall ist, reduziert sich die zulässige Verlustleistung.  In den Datenblättern findet man dazu Zahlenwerte und teilweise Diagramme zur zulässigen Verlustleistung als Funktion der Umgebungstemperatur. Je nach Wärmewiderstand '''R&amp;lt;sub&amp;gt;Th&amp;lt;/sub&amp;gt; ''' eines ggf. vorhandenen Kühlkörpers ergeben sich unterschiedliche Kurven.&lt;br /&gt;
&lt;br /&gt;
===Kenndaten===&lt;br /&gt;
Von den Kenndaten ist im wesentlichen der Stromverstärkungsfaktor ('''h&amp;lt;sub&amp;gt;FE&amp;lt;/sub&amp;gt; ''') wichtig. Für Schaltanwendungen interessiert noch die Kollektor-Emitter-Sättigungsspannung. Die anderen Kenndaten sind im wesentlichen für fortgeschrittene Schaltungen wichtig.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Autor: ZwieBack - Wiki Konvertierung Frank''&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Feldeffekttransistor|FET]]&lt;br /&gt;
* [[Kleinsignalverstärker]]&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
* [http://www.nano.physik.uni-muenchen.de/elektronik/nav/k5t2.html Grundlagen Transistorschaltungen] Anm.: Seite existiert nicht mehr&lt;br /&gt;
* [http://www.mikrocontroller.net/articles/Transistor Mikrocontroller.net/Transistor]&lt;br /&gt;
* [http://de.wikipedia.org/wiki/Transistor Wikipedia/Transistor]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Siebensegmentanzeige&amp;diff=17396</id>
		<title>Siebensegmentanzeige</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Siebensegmentanzeige&amp;diff=17396"/>
				<updated>2011-04-12T11:36:36Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Transistoren als Segmenttreiber */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dieser Artikel behandelt die Verwendung und Ansteuerungen von LED-Siebensegmentanzeigen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Siebensegmentanzeigen.jpg|thumb|300px|verschiedene LED-Siebensegmentanzeigen]]&lt;br /&gt;
&lt;br /&gt;
Siebensegmentanzeigen bestehen meist aus einer großen Anzahl von LEDs, die so in einem Gehäuse angeordnet sind, um mit einer entsprechenden Ansteuerung damit Zahlen oder auch einfache Buchstaben oder Symbole darstellen zu können.&lt;br /&gt;
&lt;br /&gt;
== Verschiendene Typen und wichtige Daten ==&lt;br /&gt;
Es sind viele verschiedene LED-Anzeigen erhältlich, man sollte sich jedoch an gewissen technischen Daten orientieren.&lt;br /&gt;
&lt;br /&gt;
* '''gemeinsame Kathode/Anode''' : In Siebensegmentanzeigen sind nicht alle Anschlüsse der LEDs einzeln herausgeführt, sondern es werden üblicherweise alle Kathoden (Minuspole) oder alle Anoden (Pluspole) der LEDs zusammengeschaltet. Die Entscheidung für gemeinsame Anode/Kathode muss mit der geplanten Schaltung zur Ansteuerung aber abgestimmt sein. Die englische Bezeichnung lautet Common Cathode oder Common Anode.&lt;br /&gt;
* '''Daten der LEDs''' : wichtig ist hierbei die Vorwärtsspannung der LEDs (meist 2V) und der empfohlene Strom durch die LEDs (meist 10-20mA). Es existieren auch Anzeigen mit Low-Current-LEDs, die mit nur 2mA auskommen. Der tatsächlich benötigte Strom hängt aber stark von der Umgebungshelligkeit und der Effizienz der LEDs ab. Große Anzeigen mit Ziffernhöhen über 20mm haben häufig mehrere LEDs pro Segment eingebaut, die elektrisch in Reihe geschaltet sind. Dann ist eine höhere Spannung zur Ansteuerung notwendig. Die Farbe der Anzeige kann nach Belieben gewählt werden, inzwischen sind auch blaue Anzeigen erhältlich, leider sind diese noch deutlich teurer als rote, gelbe oder grüne LED-Anzeigen.&lt;br /&gt;
* '''Ziffernhöhe''' : üblich sind 10mm, 13mm und 20mm. Es sind aber auch größere Anzeigen erhältlich, bis etwa 10cm Ziffernhöhe!&lt;br /&gt;
* '''Bauform''' : Es sind &amp;quot;normale&amp;quot;, also bedrahtete Anzeigen, als auch SMD-Anzeigen erhältlich. Die Pins bei den bedrahteten Anzeigen können unterschiedlich angeordnet sein, dafür lieber vorher im Datenblatt nachsehen.&lt;br /&gt;
&lt;br /&gt;
Die Segmente werden im Datenblatt üblicherweise mit Kleinbuchstaben benannt (von a bis g), DP steht für den Dezimalpunkt.&lt;br /&gt;
&lt;br /&gt;
== Varianten der Ansteuerung mit Mikrocontroller ==&lt;br /&gt;
=== direkte Ansteuerung ===&lt;br /&gt;
Diese Variante eignet sich vor allem dann, wenn nur wenige Ziffern (1 oder 2) angesteuert werden sollen.&lt;br /&gt;
&lt;br /&gt;
Der gemeinsame Anschluss (gemeinsame Kathode oder Anode) wird hierbei mit dem entsprechenden Anschluss der Versorgungsspannung verbunden. Eine gemeinsame Kathode wird mit GND verbunden, eine gemeinsame Anode mit z.B. +5V.&lt;br /&gt;
Die einzelnen Leitungen der LEDs werden dann über Vorwiderstände mit beliebigen freien Mikrocontrollerports verbunden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Siebensegment_direkt_gem_Kathode.png]]&lt;br /&gt;
&lt;br /&gt;
Im Schaltplan ist die Ansteuerung für eine Anzeige mit gemeinsamer Kathode gezeigt. Die Widerstände wurden für einen Strom von 20mA berechnet. Ein Segment wird zum Leuchten gebracht, indem die entsprechende Mikrocontrollerleitung als Ausgang und auf +5V geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
Soll eine Anzeige mit gemeinsamer Anode verwendet werden, so muss diese mit +5V verbunden werden. Ein Segment leuchtet dann auf, wenn die entsprechende Mikrocontrollerleitung als Ausgang und auf GND geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: Der Dezimalpunkt muss nur dann verbunden werden, wenn er auch später benötigt wird!&lt;br /&gt;
&lt;br /&gt;
Vorteil der Variante:&lt;br /&gt;
* Sehr einfach umzusetzen, es sind nur die Siebensegmentanzeigen und Widerstände notwendig!&lt;br /&gt;
* Hat der Mikrocontroller die Leitungen zu den LEDs ein Mal gesetzt, so leuchten die ensprechenden Segmente ständig. (Vergleiche mit Multiplexing!)&lt;br /&gt;
&lt;br /&gt;
Nachteil der Variante:&lt;br /&gt;
* nur für wenige Stellen vernünftig machbar, weil sonst zu viele Leitungen zu den LEDs benötigt werden&lt;br /&gt;
* Mikrocontroller verträgt nur einen bestimmten Gesamtstrom, der insgesamt über seine Ausgangsleitungen fließen darf. Könnte bei mehr als einer Stelle schon kritisch werden!&lt;br /&gt;
&lt;br /&gt;
=== Variante mit Schieberegistern ===&lt;br /&gt;
Für die direkte Ansteuerung werden viele Pins benötigt. Bei mehr Stellen können Schieberegister als [[Portexpander am AVR|Porterweiterung]] benutzt werden. Ein 8 Bit Schieberegister reicht dabei gerade für eine Stelle mit Dezimalpunkt. Der maximal zulässige Strom ist beim 74HC595 auf etwa 8 mA (70 mA je IC) begrenzt - das reicht von der Helligkeit in vielen Fällen, aber nicht immer. Es werden unabhängig von der Zahl der Stellen nur 3 IO Leitungen (Takt, Daten, Datenübernahme) benötigt. Dafür werden je Stelle ein IC und 7-8 Widerstände benötigt.&lt;br /&gt;
&lt;br /&gt;
=== Multiplexing ===&lt;br /&gt;
Sollen viele Stellen angezeigt werden können, würde eine direkte Ansteuerung sehr viele Pins in Anspruch nehmen. Eine bessere Möglichkeit ist dann, so genanntes Multiplexing zu verwenden. Damit werden die Stellen einzeln schnell nacheinander angesteuert. Für das menschliche Auge sind dann aber trotzdem alle Stellen gleichzeitig erkennbar.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Siebensegment_4fach_Multiplexing.png|500px]]&lt;br /&gt;
&lt;br /&gt;
Der Mikrocontroller muss nacheinander die &amp;quot;Stelle_x&amp;quot;-Anschlüsse auf +5V legen, während die anderen &amp;quot;Stelle_x&amp;quot;-Anschlüsse auf GND liegen. Zusätzlich muss dann - wie bei der direkten Ansteuerung - an die Leitungen der Segmente dann +5V angelegt werden, um das entsprechende Segment leuchten zu lassen.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: Um die gleiche Helligkeit der Anzeige wie bei der direkten Ansteuerung zu erreichen, muss der Strom durch die LED-Anzeigen erhöht werden, da diese ja nur für einen kurzen Moment mit Strom versorgt werden. Bei 4 Stellen muss der Strom durch die LEDs dann bei der Ansteuerung auch 4x so hoch sein. Für Standard-LED-Anzeigen mit 20mA Stromverbrauch pro Segment bedeutet das, dass der Mikrocontroller auf den Segmentleitungen auch 80mA treiben können müsste! Der maximale Strom liegt jedoch pro Pin bei etwa 25-50mA, sind mehrere Ausgänge geschaltet, liegt dieser Wert noch niedriger! Pro Port (z.B. gesamter PORTB) sind nur ca. 100mA Gesamtstrom zulässig, sodass die Steuerung bei diesem Strom auf diese Art und Weise der Ansteuerung bereits zum Problem wird.&lt;br /&gt;
&lt;br /&gt;
Vorteile von Multiplexing:&lt;br /&gt;
* Es können viele (bis etwa 16) Stellen angesteuert werden, nur mit Multiplexing ist dies vernünftig realisierbar.&lt;br /&gt;
* Man kommt mit deutlich weniger Pins als bei der direkten Ansteuerung aus. &lt;br /&gt;
* Es werden nur 7 bzw. 8 Widerstände für die Einstellung des Stromes benötigt.&lt;br /&gt;
* variable Helligkeit der Stellen ist ohne zusätzliche Hardware möglich.&lt;br /&gt;
&lt;br /&gt;
Nachteile von Multiplexing:&lt;br /&gt;
* Der Mikrocontroller ist ständig mit der Ansteuerung der Anzeige beschäftigt.&lt;br /&gt;
* Der Maximalstrom pro Portpin/gesamten Port (bei dieser einfachen Variante) wird zum Problem (außer bei Low-Current-Anzeigen).&lt;br /&gt;
* Bei einem Softwarefehler kann es durch den erhöhten Strom durch die Segmente passieren, dass Siebensegmentanzeigen beschädigt werden.&lt;br /&gt;
* Aufwändiges Platinenlayout notwendig, um alle Segmentleitungen der Anzeigen miteinander zu verbinden, es gibt allerdings auch Anzeigen, die für Multiplexing vorgesehen wurden und dort die Segmentleitungen bereits zusammengefasst sind.&lt;br /&gt;
&lt;br /&gt;
==== Transistoren als Segmenttreiber ====&lt;br /&gt;
&lt;br /&gt;
Um das gerade eben beschriebene Problem in den Griff zu bekommen, kann man einerseits Low-Current-Anzeigen verwenden, diese benötigen nur 2mA anstatt 20mA, sparen damit also 90% des Strombedarfes ein. Andererseits können Transistorverstärker dahinter geschaltet werden (entweder npn-Transistoren in Kollektorschaltung oder pnp-Transistoren in Emitterschaltung.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Segmenttreiber_npn_pnp.png]]&lt;br /&gt;
&lt;br /&gt;
Bei der linken Schaltung wird ein Segment zum Leuchten gebracht, wenn +5V vom Mikrocontroller angelegt wird, bei der rechten Schaltung muss dafür GND angelegt werden. Bei der Schaltung links wird über dem Transistor (CE-Strecke) noch eine Spannung von ca 0,7V abfallen (weil an der BE-Strecke 0,7V abfallen müssen, um den Transistor zu schalten. B liegt aber auf etwa +5V. Am Emitter liegen logischerweise noch etwa 4,3V an.). Bei der rechten Schaltung sind diese Verluste prinzipbedingt kleiner. Sie ist auch als 8-facher p-n-p Treiber bis 80 V und 500 mA in IC's UDN2981 bis 4 enthalten und kann, dank internem Inverter und Pegelwandler, direkt mit 5 V von einem Microcontroller gesteuert werden.&lt;br /&gt;
&lt;br /&gt;
Anmerkung: Widerstände zum Begrenzen des Stromes durch die Anzeigen müssen weiterhin verwendet werden, sie sind oben nicht eingezeichnet!&lt;br /&gt;
&lt;br /&gt;
==== Stellentreiber: ULN2003 und ULN2803 ====&lt;br /&gt;
Beim Multiplexing wurden bisher npn-Transistoren eingesetzt, um die einzelnen Stellen anzusteuern (gilt nur für gemeinsame Kathode). Da der Bauteile- und Verdrahtungsaufwand bei vielen Stellen aber steigt, ist eine Vereinfachung angebracht. Es gibt ICs, in denen bereits eine ganze Reihe Transistoren enthalten sind, um Lasten zu schalten. Die bekanntesten ICs dafür sind der ULN2003 und der ULN2803. Sie haben jeweils 7 bzw. 8 Darlingtons enthalten und können gegen GND schalten. Sie können damit die npn-Transistoren inkl. den Basisvorwiderständen ersetzen. Die ICs sind kompakt, preiswert und können das Platinenlayout einfacher gestalten. Mit einem maximalen Ausgangsstrom von 500mA pro Kanal bieten sie genug Reserve, um auch viele Stellen mittels Multiplexing ansteuern zu können. Bei einem Defekt ließe sich das IC auch rasch austauschen ( falls eine IC-Fassung verwendet wurde).&lt;br /&gt;
&lt;br /&gt;
==== Variante mit Dezimalzähler 4017 ====&lt;br /&gt;
Sollen viele Stellen angesteuert werden, so muss bei der oben gezeigten Variante pro Stelle auch ein Portpin spendiert werden. Stehen nicht genügend Ausgänge zur Verfügung, kann ein CMOS-Dezimalzähler CD4017 eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Siebensegment_4017.png]]&lt;br /&gt;
&lt;br /&gt;
Bei der Verwendung dieses ICs müssen die Ausgänge auf der rechten Seite mit den Basiswiderständen aus der obigen Schaltung verbunden werden, die Transistoren und Widerstände werden also weiterhin benötigt!&lt;br /&gt;
&lt;br /&gt;
Der Mikrocontroller muss lediglich die zwei Leitungen &amp;quot;erste Stelle&amp;quot; und &amp;quot;nächste Stelle&amp;quot; ansteuern. Für die Leitung &amp;quot;nächste Stelle&amp;quot; kann auch eine Leitung für ein Segment mit genutzt werden - das spart dann noch einen IO Pin am µC.&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
 |Reset (erste Stelle)&lt;br /&gt;
 |Clock (nächste Stelle)&lt;br /&gt;
 |Aktion&lt;br /&gt;
 |-&lt;br /&gt;
 |L&lt;br /&gt;
 |L&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
 |H&lt;br /&gt;
 |L&lt;br /&gt;
 |wähle die erste Stelle&lt;br /&gt;
 |-&lt;br /&gt;
 |L&lt;br /&gt;
 |L&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
 |L&lt;br /&gt;
 |H&lt;br /&gt;
 |nächste (2.) Stelle&lt;br /&gt;
 |-&lt;br /&gt;
 |L&lt;br /&gt;
 |L&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
 |L&lt;br /&gt;
 |H&lt;br /&gt;
 |nächste (3.) Stelle&lt;br /&gt;
 |-&lt;br /&gt;
 |L&lt;br /&gt;
 |L&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
 |usw.&lt;br /&gt;
 |usw.&lt;br /&gt;
 |usw.&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Das IC wird mit +5V und Masse versorgt und ist mit einem 100nF-Keramikkondensator abgeblockt (auf der rechten Seite des Schaltplans).&lt;br /&gt;
&lt;br /&gt;
Vorteile mit 4017:&lt;br /&gt;
* spart Portpins&lt;br /&gt;
* kann bis zu 10 Stellen ansteuern, dann müssen aber auch die Ströme durch die LEDs entsprechend erhöht werden!&lt;br /&gt;
&lt;br /&gt;
Nachteile mit 4017:&lt;br /&gt;
* es wird ein IC benötigt&lt;br /&gt;
* Reihenfolge der Stellen-Ansteuerung ist durch die Hardware festgelegt&lt;br /&gt;
&lt;br /&gt;
=== Segmenttreiber, BCD-7-Segm. ===&lt;br /&gt;
Sollen nur Ziffern dargestellt werden, können ICs eingesetzt werden, die einen BCD-Code zu Siebensegment-Leuchtkombinationen umwandeln können. Im BCD-Code werden einer Ziffer 4 Bits zugeordnet. Somit werden anstatt den 7 Segmentleitungen nur 4 Leitungen benötigt.&lt;br /&gt;
&lt;br /&gt;
Bezeichnungen dieser ICs:&lt;br /&gt;
* 7447 &lt;br /&gt;
* 74246 / 74247&lt;br /&gt;
* 4511 bzw. 74HC4511 (mit Speicher)&lt;br /&gt;
&lt;br /&gt;
Vor dem Einsatz dieser ICs sollte man ins Datenblatt schauen und dabei den maximalen Ausgangsstrom beachten, sowie ob der Treiber am Ausgang gegen GND oder gegen +5V schaltet. Leider können diese Treiber meist nur wenige mA am Ausgang schalten.&lt;br /&gt;
&lt;br /&gt;
Die BCD-7-Segment-Treiber können sowohl bei der direkten Ansteuerung als auch bei Multiplexing eingesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Erhöhung des Wirkungsgrades ===&lt;br /&gt;
Als Betriebsspannung für die Anzeigen wurde bisher 5V gewählt, die Vorwärtsspannung der LEDs liegt aber bei etwa typischen 2V. Die restliche Spannung wird im Widerstand ''verheizt''. Der Wirkungsgrad liegt hier also bei (2/5)*100%=40%. Günstiger wäre es, wenn die Differenz zwischen Betriebsspannung und LED-Vorwärtsspannung geringer wäre.&lt;br /&gt;
&lt;br /&gt;
Zum Beispiel ließe sich mit einem Schaltregler eine Spannung von 3V oder niedriger erzeugen. Im Widerstand müsste dann weniger Leistung ''verbraten'' werden. Der Einsatz eines Linearreglers macht hier natürlich keinen Sinn und erhöht auch nicht den Wirkungsgrad.&lt;br /&gt;
&lt;br /&gt;
Insgesamt ist diese Variante aber nur sinnvoll, wenn viele Stellen angesteuert werden müssen oder der Stromverbrauch der Anzeigen sehr hoch ist. &lt;br /&gt;
&lt;br /&gt;
== Vergleich mit LC-Displays ==&lt;br /&gt;
Siebensegmentanzeigen eignen sich vor allem dazu, Zahlen darzustellen. Sie haben den Vorteil, dass sie auch aus größerer Entfernung oder schlechten Lichtverhältnissen noch deutlich erkennbar sind. Außerdem bietet sich die Möglichkeit, mit wenigen ICs auch ohne Mikrocontroller Zähler oder Uhren aufbauen zu können. Die Anzeige kann darüber hinaus rasch aktualisiert werden und sind wesentlich günstiger als LC-Textdisplays.&lt;br /&gt;
&lt;br /&gt;
Vergleicht man Siebensegmentanzeigen mit handelsüblichen LC-Dotmatrix-Displays (für Text) ergeben sich allerdings deutliche Nachteile der Segmentanzeigen:&lt;br /&gt;
&lt;br /&gt;
* oft höherer Stromverbrauch der Siebensegmentanzeige (2 - 20mA pro Segment!, LC-Display: z.B. 60mA inkl. Beleuchtung)&lt;br /&gt;
* werden die Anzeigen mit einem Mikrocontroller über Multiplexing gesteuert, so ist dieser mit der Ansteuerung der Segmentanzeigen ständig beschäftigt&lt;br /&gt;
* erhöhter Bauteileaufwand (Vorwiderstände, Transistoren oder Segmenttreiber usw.)&lt;br /&gt;
* es können weniger Zeichen dargestellt werden als auf einem Display (sowohl Anzahl der Zeichen als auch Komplexität, z.B. Buchstaben, Umlaute, Symbole)&lt;br /&gt;
&lt;br /&gt;
== siehe auch ==&lt;br /&gt;
* [[RN-Digi]] Platine mit 4 Stellen per I2C zu steuern&lt;br /&gt;
&lt;br /&gt;
== Autoren ==&lt;br /&gt;
* BMS&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=17093</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=17093"/>
				<updated>2010-12-20T12:22:52Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Multitasking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich.&lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende realisiert. Als Beispiel sehe: [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=47685]]. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer unterbrochen und nächster Tast gestartet. Dafür mus immer nach Beenden der ISR unbedingt ins HP gesprungen werden und die Adresse vom PC, wo der Task unterbrochen wurde auf dem Stapel gespeichert werden. Wenn die Zeit für unterbrochener Task wieder kommt, wird er ab unterbrochener Stelle wieder in ihn zustehender Zeit ausgeführt, wieder unterbrochen u.s.w.&lt;br /&gt;
&lt;br /&gt;
Dafür muss der Stapel mit Rücksprungadressen laufend mit &amp;quot;pop&amp;quot; and &amp;quot;push&amp;quot; Befehlen bearbeitet werden, was erst ab PIC18... möglich ist Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in der sogenannten Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um einen Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn der Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=17066</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=17066"/>
				<updated>2010-12-17T09:31:32Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Hauptprogramm */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
=== Multitasking ===&lt;br /&gt;
&lt;br /&gt;
Echtes Multitasking ist nur mit mehr (Core)Prozessoren möglich.&lt;br /&gt;
&lt;br /&gt;
Sonst gibt es nur Quasi-Multitasking, das kann auf zwei Weisen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
1. Alle Tasks werden in fester bzw. per Interrupts bestimmter Reihenfolge auf Bedarf geprüft und nur die mit gesetztem Flag werden vollständig bis zum Ende realisiert. Es kann natürlich mit Proritäten für Interrupts versehen werden.&lt;br /&gt;
&lt;br /&gt;
2. Der s.g. Taskmanager (meistens HP) gibt jedem Task (meistens UP) feste Zeit und wenn der Task aktiv ist, wird er nach dieser Zeit z.B. per Timer unterbrochen und nächster Tast gestartet. Dafür mus immer nach Beenden der ISR unbedingt ins HP gesprungen werden und die Adresse vom PC, wo der Task unterbrochen wurde auf extra gerichtetem Stapel gespeichert werden. Wenn die Zeit für unterbrochener Task wieder kommt, wird er ab unterbrochener Stelle wieder in ihn zustehender Zeit ausgeführt, wieder unterbrochen u.s.w. Bei dieser Methode bei kurzen Laufzeiten für jeden Task, sieht der Beobachter praktisch keine Unterbrechungen von Tasks. Auch hier können Prioritäten benutzt werden, aber z.B. Zeiten für Warteschleifen können nicht genau berechnet werden. Das Unterbrechen von Tasks ist auch per Software-Interrupts möglich.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Sensoren&amp;diff=16909</id>
		<title>Sensoren</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Sensoren&amp;diff=16909"/>
				<updated>2010-09-05T12:01:09Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Direkte Sensoren */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Sensoren==&lt;br /&gt;
Jeder, der sich einen Roboter baut, wird schnell zu dem Punkt kommen, wo er möchte, dass sein Roboter „sieht“. &lt;br /&gt;
Sensoren müssen hauptsächlich drei Aufgaben erledigen. Die ersten beiden sind Kollisionsschutz und Navigation. Diese unterscheiden sich in der Funktionsweise vor allem in der Interpretation, im Programm und im Aufbau am Roboter. Die dritte Art sind Sensoren, die ihn mit der Umwelt in Kontakt treten lassen. &lt;br /&gt;
&lt;br /&gt;
Grundsätzlich müssen alle Sensoren diese Merkmale aufweisen: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Passiv oder aktiv?=== &lt;br /&gt;
Manche Sensoren (z.B. IR) brauchen eine aktive Quelle (hier die IR-LED), die dann aber einen Mehrverbrauch an Strom bedeutet. Passive Sensoren, wie zB Taster, bekommen ihre Signale aus der Umwelt (hier Stoß). Zu ihnen zählen die meisten Umweltgrößen, wie Temperatur und Feuchtigkeit, Licht und Vibration oder Kraft (Stoß). &lt;br /&gt;
&lt;br /&gt;
===Einfachheit===&lt;br /&gt;
Ein Sensor muss einfach sein. Denn was nützt es uns, wenn wir den Sensor nicht kalibrieren können oder der Aufbau zu schwer ist? Doch Sensoren, die nicht in einem einzigen Gehäuse untergebracht sind, sind äußerst selten. Dann besteht nur noch der Wunsch, dass die meist zweidrahtigen Sensoren auch einfach anzuschließen sind. Deswegen ist es manchmal von Vorteil, sich vorgefertigte Anschlüsse zu kaufen, anstatt diese in mühsamer Kleinarbeit selber zu erstellen. &lt;br /&gt;
&lt;br /&gt;
===Auswertbarkeit in Echtzeit===&lt;br /&gt;
Alle Sensoren, die zunächst in Frage kommen, basieren auf dem Prinzip des Spannungsteilers. Das heißt, es wird eine Urspannung eingegeben und eine Teilspannung kommt heraus. Diese Differenz können wir erfassen und mittels Wertetabelle im Programm auswerten. Aber durch Störeinflüsse in der Umwelt kann es vorkommen, dass die berechneten Werte abweichen. Jeder Messtechniker weiß, dass allein die Messung an sich schon das Messergebnis verfälscht.&lt;br /&gt;
&lt;br /&gt;
===Robustheit===&lt;br /&gt;
Wir werden am Anfang sicher nicht unseren Roboter in einer Morastlandschaft einsetzen, aber auch schon ein Stoß gegen die Wand hat manchen Roboter ausgeknockt. Schon normaler Hausstaub kann und wird Linsen trüben und Messwerte verschlechtern. Das heisst: Wenn ein Sensor gekauft wird, muss er der Situation angemessen sein.&lt;br /&gt;
&lt;br /&gt;
==Aufgaben für Roboter==&lt;br /&gt;
Natürlich muss man sich, bevor der Roboter steht, schon im Klaren sein, was seine Aufgaben sind. Auch wenn diese so weitgefasst sind wie „Karte erstellen – Raumüberwachung – dabei einer Linie folgen“. Jeder Sensor braucht Platz und verringert die Einsatzdauer. Nicht jeder Sensor ist für jede Arbeit gedacht und zum Schluss spielt das Geld eine Rolle, denn mancher Sensor kostet schon 30 Euro. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sensoren für den Kollisionsschutz===&lt;br /&gt;
Die wichtigsten Sensoren auf einem Roboter sind die Kollisionssensoren. Diese schützen den Roboter vor Zusammenstößen und Abstürzen in einen Schacht. Dabei kann man diese Gruppe in direkte und indirekte Sensoren unterteilen. &lt;br /&gt;
&lt;br /&gt;
====Direkte Sensoren====&lt;br /&gt;
Sie sollen den Zusammenstoß nicht verhindern, sondern dabei das Signal ausgeben. In letzter Zeit werden diese Sensoren noch gepolstert, damit beim Zusammenstoß keine zu großen Kräfte auftreten. &lt;br /&gt;
Am Einfachsten geht dies mit einem Taster, der am Chassis befestigt ist. Da dies sehr kurze Reaktionszeiten mit sich bringt, haben einige Roboter Fühler, um diese Zeit zu verlängern. Eine weitere Methode ist es, eine Stoßstange zu entwickeln, die dann an den Tastern (direkt oder indirekt) befestigt wird. Dabei kann diese Stoßstange auch gepolstert sein. Eine nun neuere Methode ist es, Luftschläuche zu verwenden. Die dämpfen den Stoß ab und sind dabei an einem Drucksensor angeschlossen, der das Zusammenquetschen erkennt und ein Signal ausgibt.&lt;br /&gt;
&lt;br /&gt;
Als Taster kann auch ein virtueller Bumper verwendet werden. Das Prinzip ist, eine Stromerhöhung eines Antriebsmotors beim Kollidieren mit einem Hindernis als Bumper zu emulieren. Das ermöglicht praktisch einen Roboter so zu steuern, wie wenn auf seinem ganzen Umfang echte Bumpers befestigt wären. Beim Kollidieren mit einem Hindernis wird der Ausgang der Schaltung (siehe Skizze) mit dem GND kurzgeschlossen, genauso wie wenn ein echter Bumper betätigt wäre. Hardware- bzw softwaremäßig kann man den Wirkungsbereich des virtuellen Bumpers nach individuellen Wünschen gestalten (siehe eventuell dazu http://www.roboternetz.de/phpBB2/viewtopic.php?t=49716&amp;amp;postdays=0&amp;amp;postorder=asc&amp;amp;start=66 ).&lt;br /&gt;
&lt;br /&gt;
Der Spannungsabfall auf dem Shunt (Rs) sollte bei normalem Fahren sicher unter der Spannung liegen, die der Transistor (T) zum Leiten braucht (ca. 0,7 V für normale und ca. 1,4 V für Darlington-Transistoren), z.B. 0,4 V. Bei Kollision mit einem Hindernis sollte der Spannungsabfall auf dem Rs sicher die o.g. Spannung überschreiten und z.B. 0,8 V oder höher sein. Der Elko (C) verzögert den Anstieg der Spannung auf dem Rs für den Anlaufstrom des Motors, der bis ca. 5-fach größer als beim unbehinderten Fahren ist. Für einen konkreten Motor und µC müssen die Rs, Rp (eventuell innerer pull-up) und C entsprechend angepasst werden, damit die Schaltung zufriedenstellend funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Beispielschaltung wurde fur einen DC-Getriebemotor mit folgenden Parametern entwickelt:&lt;br /&gt;
&lt;br /&gt;
- Strom beim unbehindertem Fahren: ca. 0,4 A&lt;br /&gt;
&lt;br /&gt;
- Strom beim gebremstem Motor: ca. 0,8 A&lt;br /&gt;
&lt;br /&gt;
- Anlaufstrom beim Anfahren: ca. 2 A&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                                VCC&lt;br /&gt;
                                                 +&lt;br /&gt;
                                                 |&lt;br /&gt;
                                                .-.&lt;br /&gt;
                                                | | Rp&lt;br /&gt;
                     +-----------------------+  | | 1k&lt;br /&gt;
                     |                       |  '-'&lt;br /&gt;
                     |         Rb            |   |&lt;br /&gt;
                     |                    +------+-&amp;gt; zum µC Pin&lt;br /&gt;
                     |         1k         |  |       (anstatt Bumper)&lt;br /&gt;
                     |        ___       |/   |&lt;br /&gt;
     von H-Brücke &amp;gt;--------+-|___|-+----| T  |&lt;br /&gt;
    (üblich mit GND  |     |       |    |&amp;gt;   |&lt;br /&gt;
     verbunden)      |    .-.      |+     |  |&lt;br /&gt;
                     | Rs | |     === C  === |&lt;br /&gt;
                     |    | |     /-\    GND |&lt;br /&gt;
                     |  1 '-'      | 100µ    |&lt;br /&gt;
                     |     |       |         |&lt;br /&gt;
                     |    ===     ===        |&lt;br /&gt;
                     |    GND     GND        |&lt;br /&gt;
                     |                       |&lt;br /&gt;
                     +-----------------------+&lt;br /&gt;
                         virtueller Bumper&lt;br /&gt;
&lt;br /&gt;
Als virtueller Bumper kann auch an ein Antriebsrad angebrachter Impulsgeber softwaremässig emuliert werden.&lt;br /&gt;
&lt;br /&gt;
====Indirekte Sensoren====&lt;br /&gt;
Sie sollen helfen, den Zusammenstoß zu vermeiden, um bestenfalls noch Zeit zu geben, einen optimalen Weg ums Hindernis herum zu finden. Diese haben ein größeres Problem, da sie meist keine 360-Grad-„Rundumsicht“ garantieren können. Das bedeutet, dass die meisten Roboter diesen Typ der Sensoren in Fahrtrichtung eingebaut haben, um diese Aufgabe zu erfüllen. Was auch effizient ist, denn solche Sensoren sind sehr teuer und müssen ständig vom Programm überwacht werden. &lt;br /&gt;
&lt;br /&gt;
Diese Sensoren werden bei neueren Autos auch als Parkhilfe angeboten.&lt;br /&gt;
&lt;br /&gt;
==Probleme==&lt;br /&gt;
Das Problem der Sensoren ist ihre räumliche Begrenztheit. Denn schon 5 Meter sind sehr lang. Aber auf der anderen Seite wollen die meisten ohnehin keine 5 Meter „vorausschauen“. &lt;br /&gt;
[[Sensorarten|Es gibt mehrere Typen]]. Am bekanntesten sind die [[Sensorarten#optische_Sensoren|IR-Sensoren]]. Diese sind gut für lange Distanzen, aber haben das Problem, dass sie gebündelt sind und somit Zwischenräume schwer abdecken können. Besser sind dort [[Sensorarten#Ultraschall_Sensoren|Ultraschallsensoren]], die aber teurer sind. Etwas in der Nische ist das Radar-System; es ist ein sehr aufwendiges und teueres System und die Auswertung der Daten ist komplex. Es bietet aber den besten Schutz gegen Zusammenstöße, da dieses System nicht auf einen Punkt gerichtet ist, sondern die ganze Fläche abscannt. &lt;br /&gt;
&lt;br /&gt;
Problem beider Systeme: &lt;br /&gt;
Das ist die Höhe. Leider ist unser Roboter dreidimensional und bewegt sich zweidimensional. Das heißt, es spannen sich mehrere Ebenen auf, die überwacht werden wollen. Denn wenn dies nicht geschieht, stößt der Roboter gegen eine Tischplatte, weil er diese nicht erkannt hat oder gegen ein Hindernis, das unter den Sensoren hindurch rutschte. &lt;br /&gt;
Deswegen bemüht man sich, den Roboter so flach wie möglich zu halten und das Fahrgestell so zu bauen, dass man flache Hindernisse überfahren kann. Es hilft also, sich darüber vorher Gedanken zu machen. &lt;br /&gt;
Je nachdem wo der Roboter zum Einsatz kommt tun sich manchmal Abgründe auf (z.B. Tischplatte). Diese müssen erkannt werden. Deswegen ist es erforderlich, Abstandssensoren noch unten zu richten, um einen Absturz zu vermeiden. Dabei sollte man indirekte Sensoren einsetzen, denn was nützt es, wenn der Taster erkannt hat, dass nun ein Loch da ist, aber der Roboter bis zur Reaktion schon auf dem Boden aufschlägt?&lt;br /&gt;
&lt;br /&gt;
==Navigation==&lt;br /&gt;
Nun gibt es hier viele Arten, wie die Navigation erfolgen kann. Ich tue 2 Felder auf. Wenn unser Freund neue Welten erkunden soll oder in einem Spiel gegen eine Mannschaft antritt, dann braucht er andere Sensoren, als wenn er routiniert Wege abfahren soll. Obwohl sich die Felder überschneiden. &lt;br /&gt;
&lt;br /&gt;
Alle Navigationssysteme bauen auf 2 Quellen der Navigation auf: [[Sensorarten#Drehgeber_Sharp_GP1A30|inkrementale Weggeber]] und Absolutwertgeber. &lt;br /&gt;
&lt;br /&gt;
Dies ist das größte Problem, wenn ihr einen Bot bauen wollt. Denn ihr habt das Problem nicht, das euer Bot hat. Euch ist das zu abstrakt, aber wenn ihr das nicht begreift, wird er nie dort hinkommen, wo er hin soll. Ihr habt Augen, die euch ohne zu denken den Absolutwert geben, wie weit der Abstand des Cursors eurer Maus zum Startbutton jetzt ist. Die Maus hat einen Weggeber intern, doch ihr kontrolliert ständig, ob die Werte korrekt sind und korrigiert diese falls nötig! Das kann euer Roboter nicht. Das heisst, wenn eine Achse sich schwerer dreht als die andere, wird er ständig im Kreis fahren. Ohne dass ihr das in den Messwerten sehen könnt.&lt;br /&gt;
&lt;br /&gt;
==Weggeber==&lt;br /&gt;
Die [[Sensorarten#Drehgeber_Sharp_GP1A30|Weggeber]] existieren meistens in Form der Odometrie. Das heisst, die Drehung der Antriebsachse wird direkt erfasst. Das kann erfolgen mit einem Schrittmotor (wobei dies indirekt ist, da ihr hier die Werte vorgebt) oder mit einer Lochscheibe, die dann die Schritte mittels Lichtschranke zählt. Oder mit Tastern und einem Zahnrad. &lt;br /&gt;
Nicht zur Odometrie gehörend, aber auch Weggeber, sind „mitlaufende“ zählende Räder (z.B eine Kugelmaus) oder aber eine optische Maus. Oder ein Seil, das ihr von einem Lotpunkt mitzieht. &lt;br /&gt;
&lt;br /&gt;
Diese Weggeber sind ungenau und verfälschen immer das Ergebnis. Wenn ihr den Roboter über längere Strecken fahren lässt, braucht ihr den 2. Typ, um ihn neu einzukalibrieren. &lt;br /&gt;
&lt;br /&gt;
===Absolutwertgeber:===&lt;br /&gt;
Diese Methode sagt euch, wo auf einer Ebene ihr euch exakt befindet; in X- und Y-Achse aufgesplittet. &lt;br /&gt;
&lt;br /&gt;
Es gibt mehrere Methoden, die ich ohne besondere Reihenfolge aufliste: &lt;br /&gt;
&lt;br /&gt;
====Peilung====&lt;br /&gt;
Das [[Sensorarten#Sharp_GP2D12|IR-Abstandsmessungsprinzip]] funktioniert so, dass sich ein Turm auf dem Roboter befindet. Diese Sensoren scannen den Raum ab. Mittels weiterer Sensoren ([[Sensorarten#Kompa.C3.9F|Kompasssensoren]]) kann man berechnen, wo im Raum man sich befindet. Nur bedingt einsetzbar, da ja Objekte die Wand verdecken. &lt;br /&gt;
Das Bakensystem funktioniert nach dem Einpeilungsprinzip. Das heißt, in einem Raum kennen wir mindestens 2 Punkte (Baken), die dann mit dem Roboter ein Ebenendreieck aufspannen. Mittels Berechnungen kann dann die unbekannte Roboter-Position exakt bestimmt werden. Es gibt verschiedene Methoden, doch hier die Wichtigsten: &lt;br /&gt;
&lt;br /&gt;
* Aktive Bake: Die Baken senden ein Signal aus, das dann vom Roboter empfangen wird (z.B. IR). Das ist die einfachste Methode, wenn auch nicht die eleganteste. Denn dadurch muss sich die Technik über den Roboter hinaus in den Raum ausbreiten und das wiederum kollidiert mit dem Prinzip des autonomen Roboters. Die meisten Absolutwertgeber mit Baken gehen diesen Weg. &lt;br /&gt;
&lt;br /&gt;
* Passive Bake: Nur das Signal zu dem Roboter wird zurückgesendet, das dieser ausstrahlt. Das Problem ist, dass bei diesem System der Aufwand auf dem Roboter höher ist und dass der Batterieverbauch größer wird. Aber wir haben dann auch einen wirklich autonomen Roboter. &lt;br /&gt;
&lt;br /&gt;
-Aus dem Alltag- &lt;br /&gt;
Es gibt Veranstaltungen/Wettkämpfe, die nur eine Bake zulassen. Diese soll dabei nicht helfen, um herauszufinden, wo sich der Roboter im Raum befindet, sondern nur, wo er hin soll bzw. wo sein „Feind“ ist. &lt;br /&gt;
&lt;br /&gt;
====Das Bodenmarkierungsprinzip====&lt;br /&gt;
wird meistens eingesetzt, wenn der Roboter sich nur in einem bestimmten Feld oder auf einer bestimmten Bahn aufhalten soll. Dabei werden passive oder aktive Elemente im Boden eingelassen, die dann von Onboard-Sensoren wahrgenommen werden. Beispiel hierfür sind Rasenmäherbots oder autonome Fahrzeuge in Werkshallen. &lt;br /&gt;
&lt;br /&gt;
====[[GPS]]====&lt;br /&gt;
Neben dem Bakensystem existiert noch ein raumunabhängiges System; das [[GPS]]. Dieses ist aber sehr aufwändig. Denn es bezieht Zeitsignale von Satelliten, die dann verglichen werden und ist meist draußen besser zu empfangen. Auch ließ das US-Militär das Signal verschlechtern, so dass es nur sehr ungenau war. Heutzutage ohne Störsignal schafft man auch nur Genauigkeiten von einigen Metern. Wenn man genauere Werte braucht, benötigt man mindestens 2 Empfänger und muss diese miteinander vergleichen. Einer der Empfänger steht dann normalerweise an einem festen Punkt. Das nennt sich Differential-GPS (DGPS). Näheres unter dem Artikel [[GPS]].&lt;br /&gt;
&lt;br /&gt;
Weitere Methoden sind nicht zu gebrauchen oder sind nur Abarten der hier erwähnten Methoden.&lt;br /&gt;
&lt;br /&gt;
===Umweltsensoren===&lt;br /&gt;
Sie sind meist erst in der letzten Ausbaustufe beim Roboter interessant und sollen unserem Freund helfen, sich in der Umwelt zurechtzufinden. &lt;br /&gt;
&lt;br /&gt;
Dabei gibt es Interaktionsensoren, wie Drucksensoren oder Mikrofone. Mikrofone lassen den Roboter erkennen, ob Geräusche vorhanden sind. Richtig: ob, nicht wo. Dazu muss das Mikrofon entweder gerichtet sein und sich im Raum drehen können oder aber es müssen sich Mikrofone in vier Ecken starr auf dem Roboter befinden. &lt;br /&gt;
&lt;br /&gt;
Wenn der Roboter eine Solarzelle hat, dann braucht er Lichtsensoren, die ihn zur größten Lichtquelle bringen. &lt;br /&gt;
&lt;br /&gt;
====Rauchsensoren==== lassen den Roboter zwar erkennen, dass sich Rauch im Raum befindet. Doch was nützt es, wenn dieser Rauch erst in einer Höhe von 40 cm erkannt wird? Um z.B. Räume auf Giftgas zu testen braucht es einen Gasmesser. Beide Sensoren arbeiten unterschiedlich. Während Rauchmelder alle Partikel ohne Ausnahme erkennen, haben Gasmesser nur eine begrenzte Sammlung an zu erkennenden Gasen. &lt;br /&gt;
&lt;br /&gt;
====Temperatursensoren==== ermöglichen dem Bot die Temperatur zu messen, um z.B. aus der Sonne zu gehen oder um einzelne Bauelemente vor Überhitzung zu schützen.&lt;br /&gt;
&lt;br /&gt;
==Nachsatz==&lt;br /&gt;
Es gibt dutzende Sensoren und Sensoranlagen, die unserem Bot helfen sich in der Umwelt zurechtzufinden. Je mehr man hat, umso mehr kann man mit diesen spielen, um z.B. Gewohnheiten zu programmieren. Aber wenn man seinen Bot auf eine Aufgabe ausrichtet, sind es diese, die das i-Tüpfelchen bringen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Autor: honkitonk / Wiki Übernahme Picnick''&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
* [[Sensorarten]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Sensoren]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16888</id>
		<title>PIC ASM Beispiele</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16888"/>
				<updated>2010-08-15T11:18:26Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* PIC18... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PIC12...&amp;amp; PIC16... =&lt;br /&gt;
&lt;br /&gt;
Einige ASM Beispiele für PC12... und PIC16... befinden sich in http://www.rn-wissen.de/index.php/PIC_Assembler#Codeschnipsel .&lt;br /&gt;
&lt;br /&gt;
== UART Routine ==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RS232send&lt;br /&gt;
	banksel  	TXREG			; Zur Bank von TXREG umschalten&lt;br /&gt;
	movwf	        TXREG			; Move w to TXREG &lt;br /&gt;
	banksel	        PIR1			; Zur Bank von PIR1 umschalten&lt;br /&gt;
Waittx	&lt;br /&gt;
	btfss		PIR1, TXIF		; Wenn bit in PIR1,TXIF HIGH übergehe den nästen Befehl&lt;br /&gt;
	goto		Waittx			; Gehe zu WaitTX&lt;br /&gt;
	bcf		PIR1, TXIF 		; Interrupt Flag Löschen (Optionam muss nicht umbedinkt gemacht werden)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlerbehandlung:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
uart_ferr				; Auf Frameerror testen&lt;br /&gt;
	btfsc	RCSTA, FERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_oerr				; Auf Overrunerror testen&lt;br /&gt;
	btfsc	RCSTA, OERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_err				; Fehlerbehandlung&lt;br /&gt;
	; Fehlerbehanlungsroutine hier einfügen!!!!!!!!!!!!!!!!!&lt;br /&gt;
        ; z.b. Interupt beenden und RCREG nicht sichern&lt;br /&gt;
	bcf	RCSTA, CREN		; Fehler Bits Löschen&lt;br /&gt;
	bsf	RCSTA, CREN&lt;br /&gt;
	return				; Interupt beenden und zurück zur Main schleife&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Entfangen per Interupt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int	; Interupt STATUS und W sichern&lt;br /&gt;
	movwf	wtemp			; W Sichern&lt;br /&gt;
	swapf	STATUS, w		; Status Sichern&lt;br /&gt;
	movwf	stemp			; Status Speichern&lt;br /&gt;
	btfss	PIR1, RCIF		; Interupt vom USART wenn nicht&lt;br /&gt;
	goto	intend			; Interupt beenden&lt;br /&gt;
	; Interupt Code uart&lt;br /&gt;
	call	uart_ferr		; Auf Frame Errors Testen &amp;lt;b&amp;gt;(siehe Fehlerbehandlung) &amp;lt;/b&amp;gt;&lt;br /&gt;
	call	uart_oerr		; Auf Overrunerrors Testen&lt;br /&gt;
	movf	RCREG,w			; uart RX Reg sichern&lt;br /&gt;
	movwf	rx&lt;br /&gt;
intend  ; Interupt beenden und STATUS + W zurückspielen&lt;br /&gt;
	bcf	PIR1, RCIF		; Interuptflag Löschen&lt;br /&gt;
	swapf	stemp, w		; Status restore&lt;br /&gt;
	movwf	STATUS&lt;br /&gt;
	swapf	wtemp, f		; W restore&lt;br /&gt;
	swapf	wtemp, w&lt;br /&gt;
	retfie				; Interupt Beenden&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DG-16080 Text-Mode==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrl			; LOW ADR&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrh			; High ADR&lt;br /&gt;
	call	disp_send_char		; Adressregister setzen und vorbereiten zum Daten schreiben&lt;br /&gt;
	movlw	B'01001000'		; H&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01100001'		; a&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01110101'		; u&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Display Anschlüsse:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	#define RS	PORTC, 0	; Display Command(H)/DATA(L)&lt;br /&gt;
	#define RW	PORTC, 2	; Display Read(H)/Write(L)&lt;br /&gt;
	#define E	PORTC, 3	; Display Enable&lt;br /&gt;
	#define	CS	PORTC, 4	; Display Chip Enable(L)&lt;br /&gt;
	#define	WDATA	PORTB		; Display Datenport (PORTB)&lt;br /&gt;
	#define YM	PORTA, 3	; Touch y- ADC&lt;br /&gt;
	#define YP	PORTA, 2	; Touch y+ PWR&lt;br /&gt;
	#define XP	PORTA, 4	; Touch x+ PWR&lt;br /&gt;
	#define XM	PORTA, 1	; Touch x- ADC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
dg-16080.inc&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
disp_init				; Display Inialisieren&lt;br /&gt;
	bcf	RW			; Startbedinungen herstellen&lt;br /&gt;
	nop&lt;br /&gt;
	bcf 	CS&lt;br /&gt;
	movlw	0x00			; Mode Control REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	b'00111000'		; DB5=ON/OFF, DB4=Master/Slave, DB3=Blink, DB2=Coursor, DB1/DB0=TEXT(00)/GRAFIG(10)&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x01			; Character Pitch REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x75			; 7x8px&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x02			; Nummer oh Char REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'26'			; Anzahl horit. Zeichen -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x03			; Display Duty REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x4F			; Display Duty&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x04			; Cursor Position REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'7'			; Curserstrich y-Pos -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	return&lt;br /&gt;
disp_send_c				; Send Command&lt;br /&gt;
	bsf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_send_d				; Send DATA&lt;br /&gt;
	bcf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_cls				; Display Löschen Textmode&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	D'65'&lt;br /&gt;
	movwf	count&lt;br /&gt;
disp_cls_loop&lt;br /&gt;
	movlw	B'00100000'		; 65x5&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	decfsz	count,1&lt;br /&gt;
	goto	disp_cls_loop&lt;br /&gt;
	return&lt;br /&gt;
disp_send_char				; Zeichen senden (ADRL,ADRH,Char)&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrl,w			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrh,w			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Touchscreen:&lt;br /&gt;
Config für die ADCs VREF=VDD&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	banksel	TRISA			; Zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'00001011'		; PortA I/O setzen (1=In, 0=Out) (Reinfolge RB7,RB6...)&lt;br /&gt;
	movwf	TRISA			; PortA I/O setzen&lt;br /&gt;
	banksel	ADCON1			; Zur Bank von ADCON1 umschalten&lt;br /&gt;
	movlw	B'10010100'		; Alle Analog VDD=VREF, Right jutyfy, fosc/8, AN0,1,3=AN, AN2,4-7=Dig.&lt;br /&gt;
	movwf	ADCON1			; Move w to ADCON1&lt;br /&gt;
	banksel	ADCON0			; zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'01000001'		; Enable ADC&lt;br /&gt;
	movwf	ADCON0			; Move w to ADCON0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch_read&lt;br /&gt;
	; Y&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bsf	XP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bcf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD1 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	ylow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	yhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	; X&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	bsf	YP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bsf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD3 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	xlow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	xhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	return&lt;br /&gt;
adc_read&lt;br /&gt;
	movlw	D'30'			; Wait Acquisition Time 20MHz&lt;br /&gt;
	movwf	count&lt;br /&gt;
adc_read_loop&lt;br /&gt;
	decfsz	count,F&lt;br /&gt;
	goto	adc_read_loop&lt;br /&gt;
	bsf	ADCON0,GO		; Setze ADCON0,GO, Int A/D Conversation&lt;br /&gt;
adc_read_loop_1				; Wen ADC bereit &lt;br /&gt;
	btfsc	ADCON0,GO		; Ist ADCON0,GO = 0 dann ubergehe den nesten Befehl&lt;br /&gt;
	goto	adc_read_loop_1		; Warte bis ADC fertig&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 12:00, 23. Jan 2010 (CET)&lt;br /&gt;
&lt;br /&gt;
== Schieberegister (z.b. CD4094) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; Datenleitungen Schiberegister alles Ausgänge&lt;br /&gt;
	#define		CLK		PORTB, 0&lt;br /&gt;
	#define		D	 	PORTB, 1&lt;br /&gt;
	#define		STR		PORTB, 2&lt;br /&gt;
	#define		OE		PORTB, 3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 cd4094_send&lt;br /&gt;
	banksel	PORTB&lt;br /&gt;
        bcf             OE&lt;br /&gt;
	bcf		STR&lt;br /&gt;
	btfsc	cdsend, 0&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 0&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 1&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 1&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 2&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 2&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 3&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 3&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 4&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 4&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 5&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 5&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 6&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 6&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 7&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 7&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	bsf		STR&lt;br /&gt;
        bsf             OE&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
== MAX7456 (S/W OSD) ==&lt;br /&gt;
&lt;br /&gt;
Variabeln und I/0:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	cblock	0x70		; Variabeln ab 0x70 setzen alle Register max 16stk.&lt;br /&gt;
	SPI_DATA_WRITE		; Zu Sendene SPI Daten&lt;br /&gt;
	SPI_DATA_READ		; Gelesend SPI Daten&lt;br /&gt;
	m_char			; Maxim7456 und sda5708 Zeichen&lt;br /&gt;
	m_pos			; Maxim7456 Position&lt;br /&gt;
	endc 			; Variabeln setzen beenden&lt;br /&gt;
&lt;br /&gt;
	#define	SPI_CS	PORTC, 7; SPI Slave Select max7456&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Config:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; PORTC&lt;br /&gt;
	banksel	TRISC			; auf Bank 1 umschalten&lt;br /&gt;
	movlw	B'10010000'		; PortC I/O setzen (1=In, 0=Out) (Reinfolge RC7,RC6...)&lt;br /&gt;
	movwf	TRISC			; PortC I/O setzen&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	clrf	PORTC			; PortC auf 0 setzen&lt;br /&gt;
	; SPI&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
	movlw	B'11000000'		; Mitlere Geschwindigkeit Output Time &lt;br /&gt;
	movwf	SSPSTAT&lt;br /&gt;
	banksel	SSPCON&lt;br /&gt;
	movlw	B'00100001'		; MODE 1,1, SPI MASTER, 1/16 Tosc SSP ON&lt;br /&gt;
	movwf	SSPCON&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf	SPI_CS			; SPI Slave Select aus (high)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SPI  Sende/Enfangs Rotinen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SPI_Send&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS			; Chip Select an (Low)&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SPI_DATA_WRITE, W&lt;br /&gt;
	movwf	SSPBUF&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
SPI_Wait&lt;br /&gt;
	btfss	SSPSTAT, BF		; Ist das Senden Komplet ?&lt;br /&gt;
	goto	SPI_Wait			; Wen nicht gehe zu SPIWait&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf 		SPI_CS			; Chip Select aus (High)&lt;br /&gt;
	return &lt;br /&gt;
SPI_Read&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SSPBUF, W&lt;br /&gt;
	movwf	SPI_DATA_READ&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf		SPI_CS&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Defines ASCII to MAX7456 Charset und Config und Schreibrotienen (Achtung es kann sein das die #define nicht mit mpasm Funktioniert mit gpasm wird groß und kleinschreibung unterschiden):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
max7456_define				; Defines für den max7456 Zeichensatz&lt;br /&gt;
	#define	m_sp	0x00		; Space&lt;br /&gt;
	#define	m_1		0x01&lt;br /&gt;
	#define	m_2		0x02&lt;br /&gt;
	#define	m_3		0x03&lt;br /&gt;
	#define	m_4		0x04&lt;br /&gt;
	#define	m_5		0x05&lt;br /&gt;
	#define	m_6		0x06&lt;br /&gt;
	#define	m_7		0x07&lt;br /&gt;
	#define	m_8		0x08&lt;br /&gt;
	#define	m_9		0x09&lt;br /&gt;
	#define	m_0		0x0A&lt;br /&gt;
	#define	m_A		0x0B&lt;br /&gt;
	#define	m_B		0x0C&lt;br /&gt;
	#define	m_C		0x0D&lt;br /&gt;
	#define	m_D		0x0E&lt;br /&gt;
	#define	m_E		0x0F&lt;br /&gt;
	#define	m_F		0x10&lt;br /&gt;
	#define	m_G		0x11&lt;br /&gt;
	#define	m_H		0x12&lt;br /&gt;
	#define	m_I		0x13&lt;br /&gt;
	#define	m_J		0x14&lt;br /&gt;
	#define	m_K		0x15&lt;br /&gt;
	#define	m_L		0x16&lt;br /&gt;
	#define	m_M	0x17&lt;br /&gt;
	#define	m_N		0x18&lt;br /&gt;
	#define	m_O		0x19&lt;br /&gt;
	#define	m_P		0x1A&lt;br /&gt;
	#define	m_Q		0x1B&lt;br /&gt;
	#define	m_R		0x1C&lt;br /&gt;
	#define	m_S		0x1D&lt;br /&gt;
	#define	m_T		0x1E&lt;br /&gt;
	#define	m_U		0x1F&lt;br /&gt;
	#define	m_V		0x20&lt;br /&gt;
	#define	m_W	0x21&lt;br /&gt;
	#define	m_X		0x22&lt;br /&gt;
	#define	m_Y		0x23&lt;br /&gt;
	#define	m_Z		0x24&lt;br /&gt;
	#define	m_a		0x25&lt;br /&gt;
	#define	m_b		0x26&lt;br /&gt;
	#define	m_c		0x27&lt;br /&gt;
	#define	m_d		0x28&lt;br /&gt;
	#define	m_e		0x29&lt;br /&gt;
	#define	m_f		0x2A&lt;br /&gt;
	#define	m_g		0x2B&lt;br /&gt;
	#define	m_h		0x2C&lt;br /&gt;
	#define	m_i		0x2D&lt;br /&gt;
	#define	m_j		0x2E&lt;br /&gt;
	#define	m_k		0x2F&lt;br /&gt;
	#define	m_l		0x30&lt;br /&gt;
	#define	m_m		0x31&lt;br /&gt;
	#define	m_n		0x32&lt;br /&gt;
	#define	m_o		0x33&lt;br /&gt;
	#define	m_p		0x34&lt;br /&gt;
	#define	m_q		0x35&lt;br /&gt;
	#define	m_r		0x36&lt;br /&gt;
	#define	m_s		0x37&lt;br /&gt;
	#define	m_t		0x38&lt;br /&gt;
	#define	m_u		0x39&lt;br /&gt;
	#define	m_v		0x3A&lt;br /&gt;
	#define	m_w		0x3B&lt;br /&gt;
	#define	m_x		0x3C&lt;br /&gt;
	#define	m_y		0x3D&lt;br /&gt;
	#define	m_z		0x3E&lt;br /&gt;
	#define	m_KLa	0x3F	; (&lt;br /&gt;
	#define	m_KLz	0x40		; )&lt;br /&gt;
	#define	m_.		0x41&lt;br /&gt;
	#define	m_?		0x42&lt;br /&gt;
	#define	m_sem	0x43		; ;&lt;br /&gt;
	#define	m_:		0x44&lt;br /&gt;
	#define	m_ko	0x45		; ,&lt;br /&gt;
	#define	m_ag	0x46		; Agostroff&lt;br /&gt;
	#define	m_bs	0x47		; Backslasch&lt;br /&gt;
	#define	m_as	0x48		; Anfürungsstriche&lt;br /&gt;
	#define	m_minus  0x49		; Minus&lt;br /&gt;
	#define	m_ka	0x4A		; &amp;lt;&lt;br /&gt;
	#define	m_ga	0x4B	; &amp;gt;&lt;br /&gt;
	#define	m_at	0x4C	; @ oder at&lt;br /&gt;
	#define	m_wait	0xfb		; Wartezeichen&lt;br /&gt;
	#define	m_ls		0xf9		; Lautsprecher&lt;br /&gt;
	#define	m_lso	0xfa		; Tonsignal&lt;br /&gt;
	#define	m_ff		0xff		; Ausgefültes feld&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_conf					; Max7456 Config&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001000'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 0=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x01				; VM1 Video Mode Register 1&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00000100'		; 0 = NA, 000=Background MODE Brightness 100%, 11=Blinking Time 160ms, 00=Blinking Duty Cycle BT:BT&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x02				; HOS Horizontal Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00101111'		; 00 = NA, 100000 = Horitzontal Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x03				; VOS Vertical Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00010111'		; 000 = NA, 10000 = Vertical Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_cls					; max7456 ausgabe Löschen&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001010'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 1=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	call		max7456_conf&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_high				; High adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 0x00, Letzten 256 Zeichen High=0xff &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0xFF&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_low				; Low Adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 000, Letzten 256 Zeichen High=225 &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_send_char&lt;br /&gt;
	movlw	0x06				; Zeichen Position links nach rechts erste reihe 0-29, 30-......&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_pos, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x07				; Zeichen Sonderzeichen sihe Define in max7456.inc&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_char, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeichen Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	D'12'			; Position&lt;br /&gt;
	movwf	m_pos&lt;br /&gt;
	movlw	m_e			; Zeichen (hier das kleine e) oder direkt den wert des Zeichens im MAX7456 REG.&lt;br /&gt;
	movwf	m_char&lt;br /&gt;
	call	max7456_send_char; Schreiben&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
High/low Adressbereich (low = ersten 256 Zeichen, High die letzten 128 Zeichen);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	call		max7456_add_low	; Low Adressbereich&lt;br /&gt;
	;call		max7456_add_high; Low Adressbereich&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
= PIC18... =&lt;br /&gt;
&lt;br /&gt;
Alle Programmfragmente stellen meistens Unteprogramme, die mit &amp;quot;call&amp;quot; bzw. &amp;quot;rcall&amp;quot; aufrufbar sind. Sie wurden mit PAD erstellt und sind daher fast nicht kommentiert&lt;br /&gt;
&lt;br /&gt;
== Programmspeicher (Flash) beschreiben und lesen ==&lt;br /&gt;
&lt;br /&gt;
Zuerst wird der benötigte Flash-Bereich gelöscht und danach werden dort Daten aus RAM kopiert (gespeichert). Dazu wurden zwei Register &amp;quot;Tmp&amp;quot; und &amp;quot;Tmp1&amp;quot; benutzt, die im Program definiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
 Store		movff	F2,FS2&lt;br /&gt;
 		movff	F1,FS1&lt;br /&gt;
 		movff	F0,FS0&lt;br /&gt;
 		clrf	TBLPTRU			; erase flash memory (7BC0-7FFF)&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		movlw	0x11&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 FlashEraseL	bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bsf	EECON1,FREE&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		bra	$-2&lt;br /&gt;
 		movlw	0x40&lt;br /&gt;
 		addwf	TBLPTRL&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		incf	TBLPTRH,1&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	FlashEraseL&lt;br /&gt;
 		lfsr	FSR0,0x0020		; write parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	4&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgPL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFPL	movff	POSTINC0,TABLAT&lt;br /&gt;
 		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFPL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgPL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 WriteSMP	lfsr	FSR0,0x100		; write samples 1024 bytes (7C00-7FFF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFL		movff	POSTINC0,TABLAT&lt;br /&gt;
  		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Um die Daten aus Flash zurück auf ursprüngliche Adressen im RAM zu übertragen, wurde folgendes Programmfragment verwendet in dem Register &amp;quot;STmp&amp;quot; benutzt wurde, der auch im Programm definiert werden muss.&lt;br /&gt;
&lt;br /&gt;
 Restore		lfsr	FSR0,0x0020		; restore parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 FlashRAMP	movlw	0x20&lt;br /&gt;
 		movwf	STmp&lt;br /&gt;
 FlashRAMPL	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAMPL&lt;br /&gt;
 		lfsr	FSR0,0x100		; restore samples 1024 bytes (7C00-7FFF)	&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 FlashRAM	clrf	STmp&lt;br /&gt;
 FlashRAML	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAML&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
== Hex Dec Wandlung ==&lt;br /&gt;
&lt;br /&gt;
Genaue Funktionsweise und Definitionen der Register sind im http://www.rn-wissen.de/index.php/PIC_Assembler#Hex_Dec_Wandlung beschrieben.&lt;br /&gt;
&lt;br /&gt;
Übrigens, das UP wurde ursprünglich für PIC18... erstellt und danach auf PIC12.. und PIC16... umgeschrieben. Durchs Vergleichen sieht man den Unterschied zwischen den PIC Familien.&lt;br /&gt;
&lt;br /&gt;
 Hex_Dec		call	CClr			; Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		call	DClr&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x18			; 24 bit Hex (6 Ziffer) &amp;gt; 32 bit Dec (8 Ziffer)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 Hex_DecL	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		bra	Hex_DecL&lt;br /&gt;
 		return&lt;br /&gt;
 CClr		lfsr	FSR0,C4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		bra	RegClr&lt;br /&gt;
 DClr		lfsr	FSR0,D4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 RegClr		movwf	ATmp&lt;br /&gt;
 RegClrL		clrf	POSTINC0&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	RegClrL&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		lfsr	FSR0,C0&lt;br /&gt;
 		lfsr	FSR1,B0&lt;br /&gt;
 CopyReg		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 CopyRegL	movff	POSTDEC0,POSTDEC1       ; INDF0 in INDF1 kopieren und Zeiger dekrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	CopyRegL		&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		lfsr	FSR0,B0			; C+B&amp;gt;C&lt;br /&gt;
 		lfsr	FSR1,C0&lt;br /&gt;
 		bra	AddReg&lt;br /&gt;
 AddDC		lfsr	FSR0,C0			; D+C&amp;gt;D&lt;br /&gt;
 		lfsr	FSR1,D0&lt;br /&gt;
 AddReg		bcf	_Ferr&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRegL		bcf	_Fcra&lt;br /&gt;
 		movf	INDF0,0&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		bra	AddRegN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddRegN		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTDEC0,1              ; Zeiger für INDF0 um 1 dekrementieren&lt;br /&gt;
 		movf	POSTDEC1,1              ; Zeiger für INDF1 um 1 decrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	AddRegL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		lfsr	FSR0,A2	&lt;br /&gt;
 RRotRb		movlw	3			; A Rregister um 1 bit nach rechts rotieren&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL		bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF0,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrcf	INDF0,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTINC0,1              ; Zeiger für INDF0 um 1 inkrementieren             &lt;br /&gt;
 		decfsz	RTmp,1&lt;br /&gt;
 		bra	RRotRbL&lt;br /&gt;
 		return &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16887</id>
		<title>PIC ASM Beispiele</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16887"/>
				<updated>2010-08-15T11:13:22Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Hex Dec Wandlung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PIC12...&amp;amp; PIC16... =&lt;br /&gt;
&lt;br /&gt;
Einige ASM Beispiele für PC12... und PIC16... befinden sich in http://www.rn-wissen.de/index.php/PIC_Assembler#Codeschnipsel .&lt;br /&gt;
&lt;br /&gt;
== UART Routine ==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RS232send&lt;br /&gt;
	banksel  	TXREG			; Zur Bank von TXREG umschalten&lt;br /&gt;
	movwf	        TXREG			; Move w to TXREG &lt;br /&gt;
	banksel	        PIR1			; Zur Bank von PIR1 umschalten&lt;br /&gt;
Waittx	&lt;br /&gt;
	btfss		PIR1, TXIF		; Wenn bit in PIR1,TXIF HIGH übergehe den nästen Befehl&lt;br /&gt;
	goto		Waittx			; Gehe zu WaitTX&lt;br /&gt;
	bcf		PIR1, TXIF 		; Interrupt Flag Löschen (Optionam muss nicht umbedinkt gemacht werden)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlerbehandlung:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
uart_ferr				; Auf Frameerror testen&lt;br /&gt;
	btfsc	RCSTA, FERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_oerr				; Auf Overrunerror testen&lt;br /&gt;
	btfsc	RCSTA, OERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_err				; Fehlerbehandlung&lt;br /&gt;
	; Fehlerbehanlungsroutine hier einfügen!!!!!!!!!!!!!!!!!&lt;br /&gt;
        ; z.b. Interupt beenden und RCREG nicht sichern&lt;br /&gt;
	bcf	RCSTA, CREN		; Fehler Bits Löschen&lt;br /&gt;
	bsf	RCSTA, CREN&lt;br /&gt;
	return				; Interupt beenden und zurück zur Main schleife&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Entfangen per Interupt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int	; Interupt STATUS und W sichern&lt;br /&gt;
	movwf	wtemp			; W Sichern&lt;br /&gt;
	swapf	STATUS, w		; Status Sichern&lt;br /&gt;
	movwf	stemp			; Status Speichern&lt;br /&gt;
	btfss	PIR1, RCIF		; Interupt vom USART wenn nicht&lt;br /&gt;
	goto	intend			; Interupt beenden&lt;br /&gt;
	; Interupt Code uart&lt;br /&gt;
	call	uart_ferr		; Auf Frame Errors Testen &amp;lt;b&amp;gt;(siehe Fehlerbehandlung) &amp;lt;/b&amp;gt;&lt;br /&gt;
	call	uart_oerr		; Auf Overrunerrors Testen&lt;br /&gt;
	movf	RCREG,w			; uart RX Reg sichern&lt;br /&gt;
	movwf	rx&lt;br /&gt;
intend  ; Interupt beenden und STATUS + W zurückspielen&lt;br /&gt;
	bcf	PIR1, RCIF		; Interuptflag Löschen&lt;br /&gt;
	swapf	stemp, w		; Status restore&lt;br /&gt;
	movwf	STATUS&lt;br /&gt;
	swapf	wtemp, f		; W restore&lt;br /&gt;
	swapf	wtemp, w&lt;br /&gt;
	retfie				; Interupt Beenden&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DG-16080 Text-Mode==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrl			; LOW ADR&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrh			; High ADR&lt;br /&gt;
	call	disp_send_char		; Adressregister setzen und vorbereiten zum Daten schreiben&lt;br /&gt;
	movlw	B'01001000'		; H&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01100001'		; a&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01110101'		; u&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Display Anschlüsse:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	#define RS	PORTC, 0	; Display Command(H)/DATA(L)&lt;br /&gt;
	#define RW	PORTC, 2	; Display Read(H)/Write(L)&lt;br /&gt;
	#define E	PORTC, 3	; Display Enable&lt;br /&gt;
	#define	CS	PORTC, 4	; Display Chip Enable(L)&lt;br /&gt;
	#define	WDATA	PORTB		; Display Datenport (PORTB)&lt;br /&gt;
	#define YM	PORTA, 3	; Touch y- ADC&lt;br /&gt;
	#define YP	PORTA, 2	; Touch y+ PWR&lt;br /&gt;
	#define XP	PORTA, 4	; Touch x+ PWR&lt;br /&gt;
	#define XM	PORTA, 1	; Touch x- ADC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
dg-16080.inc&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
disp_init				; Display Inialisieren&lt;br /&gt;
	bcf	RW			; Startbedinungen herstellen&lt;br /&gt;
	nop&lt;br /&gt;
	bcf 	CS&lt;br /&gt;
	movlw	0x00			; Mode Control REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	b'00111000'		; DB5=ON/OFF, DB4=Master/Slave, DB3=Blink, DB2=Coursor, DB1/DB0=TEXT(00)/GRAFIG(10)&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x01			; Character Pitch REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x75			; 7x8px&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x02			; Nummer oh Char REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'26'			; Anzahl horit. Zeichen -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x03			; Display Duty REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x4F			; Display Duty&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x04			; Cursor Position REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'7'			; Curserstrich y-Pos -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	return&lt;br /&gt;
disp_send_c				; Send Command&lt;br /&gt;
	bsf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_send_d				; Send DATA&lt;br /&gt;
	bcf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_cls				; Display Löschen Textmode&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	D'65'&lt;br /&gt;
	movwf	count&lt;br /&gt;
disp_cls_loop&lt;br /&gt;
	movlw	B'00100000'		; 65x5&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	decfsz	count,1&lt;br /&gt;
	goto	disp_cls_loop&lt;br /&gt;
	return&lt;br /&gt;
disp_send_char				; Zeichen senden (ADRL,ADRH,Char)&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrl,w			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrh,w			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Touchscreen:&lt;br /&gt;
Config für die ADCs VREF=VDD&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	banksel	TRISA			; Zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'00001011'		; PortA I/O setzen (1=In, 0=Out) (Reinfolge RB7,RB6...)&lt;br /&gt;
	movwf	TRISA			; PortA I/O setzen&lt;br /&gt;
	banksel	ADCON1			; Zur Bank von ADCON1 umschalten&lt;br /&gt;
	movlw	B'10010100'		; Alle Analog VDD=VREF, Right jutyfy, fosc/8, AN0,1,3=AN, AN2,4-7=Dig.&lt;br /&gt;
	movwf	ADCON1			; Move w to ADCON1&lt;br /&gt;
	banksel	ADCON0			; zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'01000001'		; Enable ADC&lt;br /&gt;
	movwf	ADCON0			; Move w to ADCON0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch_read&lt;br /&gt;
	; Y&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bsf	XP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bcf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD1 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	ylow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	yhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	; X&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	bsf	YP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bsf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD3 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	xlow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	xhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	return&lt;br /&gt;
adc_read&lt;br /&gt;
	movlw	D'30'			; Wait Acquisition Time 20MHz&lt;br /&gt;
	movwf	count&lt;br /&gt;
adc_read_loop&lt;br /&gt;
	decfsz	count,F&lt;br /&gt;
	goto	adc_read_loop&lt;br /&gt;
	bsf	ADCON0,GO		; Setze ADCON0,GO, Int A/D Conversation&lt;br /&gt;
adc_read_loop_1				; Wen ADC bereit &lt;br /&gt;
	btfsc	ADCON0,GO		; Ist ADCON0,GO = 0 dann ubergehe den nesten Befehl&lt;br /&gt;
	goto	adc_read_loop_1		; Warte bis ADC fertig&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 12:00, 23. Jan 2010 (CET)&lt;br /&gt;
&lt;br /&gt;
== Schieberegister (z.b. CD4094) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; Datenleitungen Schiberegister alles Ausgänge&lt;br /&gt;
	#define		CLK		PORTB, 0&lt;br /&gt;
	#define		D	 	PORTB, 1&lt;br /&gt;
	#define		STR		PORTB, 2&lt;br /&gt;
	#define		OE		PORTB, 3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 cd4094_send&lt;br /&gt;
	banksel	PORTB&lt;br /&gt;
        bcf             OE&lt;br /&gt;
	bcf		STR&lt;br /&gt;
	btfsc	cdsend, 0&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 0&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 1&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 1&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 2&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 2&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 3&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 3&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 4&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 4&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 5&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 5&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 6&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 6&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 7&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 7&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	bsf		STR&lt;br /&gt;
        bsf             OE&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
== MAX7456 (S/W OSD) ==&lt;br /&gt;
&lt;br /&gt;
Variabeln und I/0:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	cblock	0x70		; Variabeln ab 0x70 setzen alle Register max 16stk.&lt;br /&gt;
	SPI_DATA_WRITE		; Zu Sendene SPI Daten&lt;br /&gt;
	SPI_DATA_READ		; Gelesend SPI Daten&lt;br /&gt;
	m_char			; Maxim7456 und sda5708 Zeichen&lt;br /&gt;
	m_pos			; Maxim7456 Position&lt;br /&gt;
	endc 			; Variabeln setzen beenden&lt;br /&gt;
&lt;br /&gt;
	#define	SPI_CS	PORTC, 7; SPI Slave Select max7456&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Config:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; PORTC&lt;br /&gt;
	banksel	TRISC			; auf Bank 1 umschalten&lt;br /&gt;
	movlw	B'10010000'		; PortC I/O setzen (1=In, 0=Out) (Reinfolge RC7,RC6...)&lt;br /&gt;
	movwf	TRISC			; PortC I/O setzen&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	clrf	PORTC			; PortC auf 0 setzen&lt;br /&gt;
	; SPI&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
	movlw	B'11000000'		; Mitlere Geschwindigkeit Output Time &lt;br /&gt;
	movwf	SSPSTAT&lt;br /&gt;
	banksel	SSPCON&lt;br /&gt;
	movlw	B'00100001'		; MODE 1,1, SPI MASTER, 1/16 Tosc SSP ON&lt;br /&gt;
	movwf	SSPCON&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf	SPI_CS			; SPI Slave Select aus (high)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SPI  Sende/Enfangs Rotinen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SPI_Send&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS			; Chip Select an (Low)&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SPI_DATA_WRITE, W&lt;br /&gt;
	movwf	SSPBUF&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
SPI_Wait&lt;br /&gt;
	btfss	SSPSTAT, BF		; Ist das Senden Komplet ?&lt;br /&gt;
	goto	SPI_Wait			; Wen nicht gehe zu SPIWait&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf 		SPI_CS			; Chip Select aus (High)&lt;br /&gt;
	return &lt;br /&gt;
SPI_Read&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SSPBUF, W&lt;br /&gt;
	movwf	SPI_DATA_READ&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf		SPI_CS&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Defines ASCII to MAX7456 Charset und Config und Schreibrotienen (Achtung es kann sein das die #define nicht mit mpasm Funktioniert mit gpasm wird groß und kleinschreibung unterschiden):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
max7456_define				; Defines für den max7456 Zeichensatz&lt;br /&gt;
	#define	m_sp	0x00		; Space&lt;br /&gt;
	#define	m_1		0x01&lt;br /&gt;
	#define	m_2		0x02&lt;br /&gt;
	#define	m_3		0x03&lt;br /&gt;
	#define	m_4		0x04&lt;br /&gt;
	#define	m_5		0x05&lt;br /&gt;
	#define	m_6		0x06&lt;br /&gt;
	#define	m_7		0x07&lt;br /&gt;
	#define	m_8		0x08&lt;br /&gt;
	#define	m_9		0x09&lt;br /&gt;
	#define	m_0		0x0A&lt;br /&gt;
	#define	m_A		0x0B&lt;br /&gt;
	#define	m_B		0x0C&lt;br /&gt;
	#define	m_C		0x0D&lt;br /&gt;
	#define	m_D		0x0E&lt;br /&gt;
	#define	m_E		0x0F&lt;br /&gt;
	#define	m_F		0x10&lt;br /&gt;
	#define	m_G		0x11&lt;br /&gt;
	#define	m_H		0x12&lt;br /&gt;
	#define	m_I		0x13&lt;br /&gt;
	#define	m_J		0x14&lt;br /&gt;
	#define	m_K		0x15&lt;br /&gt;
	#define	m_L		0x16&lt;br /&gt;
	#define	m_M	0x17&lt;br /&gt;
	#define	m_N		0x18&lt;br /&gt;
	#define	m_O		0x19&lt;br /&gt;
	#define	m_P		0x1A&lt;br /&gt;
	#define	m_Q		0x1B&lt;br /&gt;
	#define	m_R		0x1C&lt;br /&gt;
	#define	m_S		0x1D&lt;br /&gt;
	#define	m_T		0x1E&lt;br /&gt;
	#define	m_U		0x1F&lt;br /&gt;
	#define	m_V		0x20&lt;br /&gt;
	#define	m_W	0x21&lt;br /&gt;
	#define	m_X		0x22&lt;br /&gt;
	#define	m_Y		0x23&lt;br /&gt;
	#define	m_Z		0x24&lt;br /&gt;
	#define	m_a		0x25&lt;br /&gt;
	#define	m_b		0x26&lt;br /&gt;
	#define	m_c		0x27&lt;br /&gt;
	#define	m_d		0x28&lt;br /&gt;
	#define	m_e		0x29&lt;br /&gt;
	#define	m_f		0x2A&lt;br /&gt;
	#define	m_g		0x2B&lt;br /&gt;
	#define	m_h		0x2C&lt;br /&gt;
	#define	m_i		0x2D&lt;br /&gt;
	#define	m_j		0x2E&lt;br /&gt;
	#define	m_k		0x2F&lt;br /&gt;
	#define	m_l		0x30&lt;br /&gt;
	#define	m_m		0x31&lt;br /&gt;
	#define	m_n		0x32&lt;br /&gt;
	#define	m_o		0x33&lt;br /&gt;
	#define	m_p		0x34&lt;br /&gt;
	#define	m_q		0x35&lt;br /&gt;
	#define	m_r		0x36&lt;br /&gt;
	#define	m_s		0x37&lt;br /&gt;
	#define	m_t		0x38&lt;br /&gt;
	#define	m_u		0x39&lt;br /&gt;
	#define	m_v		0x3A&lt;br /&gt;
	#define	m_w		0x3B&lt;br /&gt;
	#define	m_x		0x3C&lt;br /&gt;
	#define	m_y		0x3D&lt;br /&gt;
	#define	m_z		0x3E&lt;br /&gt;
	#define	m_KLa	0x3F	; (&lt;br /&gt;
	#define	m_KLz	0x40		; )&lt;br /&gt;
	#define	m_.		0x41&lt;br /&gt;
	#define	m_?		0x42&lt;br /&gt;
	#define	m_sem	0x43		; ;&lt;br /&gt;
	#define	m_:		0x44&lt;br /&gt;
	#define	m_ko	0x45		; ,&lt;br /&gt;
	#define	m_ag	0x46		; Agostroff&lt;br /&gt;
	#define	m_bs	0x47		; Backslasch&lt;br /&gt;
	#define	m_as	0x48		; Anfürungsstriche&lt;br /&gt;
	#define	m_minus  0x49		; Minus&lt;br /&gt;
	#define	m_ka	0x4A		; &amp;lt;&lt;br /&gt;
	#define	m_ga	0x4B	; &amp;gt;&lt;br /&gt;
	#define	m_at	0x4C	; @ oder at&lt;br /&gt;
	#define	m_wait	0xfb		; Wartezeichen&lt;br /&gt;
	#define	m_ls		0xf9		; Lautsprecher&lt;br /&gt;
	#define	m_lso	0xfa		; Tonsignal&lt;br /&gt;
	#define	m_ff		0xff		; Ausgefültes feld&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_conf					; Max7456 Config&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001000'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 0=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x01				; VM1 Video Mode Register 1&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00000100'		; 0 = NA, 000=Background MODE Brightness 100%, 11=Blinking Time 160ms, 00=Blinking Duty Cycle BT:BT&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x02				; HOS Horizontal Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00101111'		; 00 = NA, 100000 = Horitzontal Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x03				; VOS Vertical Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00010111'		; 000 = NA, 10000 = Vertical Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_cls					; max7456 ausgabe Löschen&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001010'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 1=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	call		max7456_conf&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_high				; High adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 0x00, Letzten 256 Zeichen High=0xff &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0xFF&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_low				; Low Adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 000, Letzten 256 Zeichen High=225 &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_send_char&lt;br /&gt;
	movlw	0x06				; Zeichen Position links nach rechts erste reihe 0-29, 30-......&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_pos, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x07				; Zeichen Sonderzeichen sihe Define in max7456.inc&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_char, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeichen Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	D'12'			; Position&lt;br /&gt;
	movwf	m_pos&lt;br /&gt;
	movlw	m_e			; Zeichen (hier das kleine e) oder direkt den wert des Zeichens im MAX7456 REG.&lt;br /&gt;
	movwf	m_char&lt;br /&gt;
	call	max7456_send_char; Schreiben&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
High/low Adressbereich (low = ersten 256 Zeichen, High die letzten 128 Zeichen);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	call		max7456_add_low	; Low Adressbereich&lt;br /&gt;
	;call		max7456_add_high; Low Adressbereich&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
= PIC18... =&lt;br /&gt;
&lt;br /&gt;
== Programmspeicher (Flash) beschreiben und lesen ==&lt;br /&gt;
&lt;br /&gt;
Zuerst wird der benötigte Flash-Bereich gelöscht und danach werden dort Daten aus RAM kopiert (gespeichert). Dazu wurden zwei Register &amp;quot;Tmp&amp;quot; und &amp;quot;Tmp1&amp;quot; benutzt, die im Program definiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
 Store		movff	F2,FS2&lt;br /&gt;
 		movff	F1,FS1&lt;br /&gt;
 		movff	F0,FS0&lt;br /&gt;
 		clrf	TBLPTRU			; erase flash memory (7BC0-7FFF)&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		movlw	0x11&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 FlashEraseL	bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bsf	EECON1,FREE&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		bra	$-2&lt;br /&gt;
 		movlw	0x40&lt;br /&gt;
 		addwf	TBLPTRL&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		incf	TBLPTRH,1&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	FlashEraseL&lt;br /&gt;
 		lfsr	FSR0,0x0020		; write parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	4&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgPL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFPL	movff	POSTINC0,TABLAT&lt;br /&gt;
 		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFPL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgPL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 WriteSMP	lfsr	FSR0,0x100		; write samples 1024 bytes (7C00-7FFF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFL		movff	POSTINC0,TABLAT&lt;br /&gt;
  		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Um die Daten aus Flash zurück auf ursprüngliche Adressen im RAM zu übertragen, wurde folgendes Programmfragment verwendet in dem Register &amp;quot;STmp&amp;quot; benutzt wurde, der auch im Programm definiert werden muss.&lt;br /&gt;
&lt;br /&gt;
 Restore		lfsr	FSR0,0x0020		; restore parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 FlashRAMP	movlw	0x20&lt;br /&gt;
 		movwf	STmp&lt;br /&gt;
 FlashRAMPL	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAMPL&lt;br /&gt;
 		lfsr	FSR0,0x100		; restore samples 1024 bytes (7C00-7FFF)	&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 FlashRAM	clrf	STmp&lt;br /&gt;
 FlashRAML	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAML&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
== Hex Dec Wandlung ==&lt;br /&gt;
&lt;br /&gt;
Genaue Funktionsweise und Definitionen der Register sind im http://www.rn-wissen.de/index.php/PIC_Assembler#Hex_Dec_Wandlung beschrieben.&lt;br /&gt;
&lt;br /&gt;
Übrigens, das UP wurde ursprünglich für PIC18... erstellt und danach auf PIC12.. und PIC16... umgeschrieben. Durchs Vergleichen sieht man den Unterschied zwischen den PIC Familien.&lt;br /&gt;
&lt;br /&gt;
 Hex_Dec		call	CClr			; Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		call	DClr&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x18			; 24 bit Hex (6 Ziffer) &amp;gt; 32 bit Dec (8 Ziffer)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 Hex_DecL	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		bra	Hex_DecL&lt;br /&gt;
 		return&lt;br /&gt;
 CClr		lfsr	FSR0,C4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		bra	RegClr&lt;br /&gt;
 DClr		lfsr	FSR0,D4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 RegClr		movwf	ATmp&lt;br /&gt;
 RegClrL		clrf	POSTINC0&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	RegClrL&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		lfsr	FSR0,C0&lt;br /&gt;
 		lfsr	FSR1,B0&lt;br /&gt;
 CopyReg		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 CopyRegL	movff	POSTDEC0,POSTDEC1       ; INDF0 in INDF1 kopieren und Zeiger dekrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	CopyRegL		&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		lfsr	FSR0,B0			; C+B&amp;gt;C&lt;br /&gt;
 		lfsr	FSR1,C0&lt;br /&gt;
 		bra	AddReg&lt;br /&gt;
 AddDC		lfsr	FSR0,C0			; D+C&amp;gt;D&lt;br /&gt;
 		lfsr	FSR1,D0&lt;br /&gt;
 AddReg		bcf	_Ferr&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRegL		bcf	_Fcra&lt;br /&gt;
 		movf	INDF0,0&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		bra	AddRegN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddRegN		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTDEC0,1              ; Zeiger für INDF0 um 1 dekrementieren&lt;br /&gt;
 		movf	POSTDEC1,1              ; Zeiger für INDF1 um 1 decrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	AddRegL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		lfsr	FSR0,A2	&lt;br /&gt;
 RRotRb		movlw	3			; A Rregister um 1 bit nach rechts rotieren&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL		bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF0,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrcf	INDF0,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTINC0,1              ; Zeiger für INDF0 um 1 inkrementieren             &lt;br /&gt;
 		decfsz	RTmp,1&lt;br /&gt;
 		bra	RRotRbL&lt;br /&gt;
 		return &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16886</id>
		<title>PIC ASM Beispiele</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16886"/>
				<updated>2010-08-15T11:12:27Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Programmspeicher (Flash) beschreiben und lesen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PIC12...&amp;amp; PIC16... =&lt;br /&gt;
&lt;br /&gt;
Einige ASM Beispiele für PC12... und PIC16... befinden sich in http://www.rn-wissen.de/index.php/PIC_Assembler#Codeschnipsel .&lt;br /&gt;
&lt;br /&gt;
== UART Routine ==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RS232send&lt;br /&gt;
	banksel  	TXREG			; Zur Bank von TXREG umschalten&lt;br /&gt;
	movwf	        TXREG			; Move w to TXREG &lt;br /&gt;
	banksel	        PIR1			; Zur Bank von PIR1 umschalten&lt;br /&gt;
Waittx	&lt;br /&gt;
	btfss		PIR1, TXIF		; Wenn bit in PIR1,TXIF HIGH übergehe den nästen Befehl&lt;br /&gt;
	goto		Waittx			; Gehe zu WaitTX&lt;br /&gt;
	bcf		PIR1, TXIF 		; Interrupt Flag Löschen (Optionam muss nicht umbedinkt gemacht werden)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlerbehandlung:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
uart_ferr				; Auf Frameerror testen&lt;br /&gt;
	btfsc	RCSTA, FERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_oerr				; Auf Overrunerror testen&lt;br /&gt;
	btfsc	RCSTA, OERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_err				; Fehlerbehandlung&lt;br /&gt;
	; Fehlerbehanlungsroutine hier einfügen!!!!!!!!!!!!!!!!!&lt;br /&gt;
        ; z.b. Interupt beenden und RCREG nicht sichern&lt;br /&gt;
	bcf	RCSTA, CREN		; Fehler Bits Löschen&lt;br /&gt;
	bsf	RCSTA, CREN&lt;br /&gt;
	return				; Interupt beenden und zurück zur Main schleife&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Entfangen per Interupt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int	; Interupt STATUS und W sichern&lt;br /&gt;
	movwf	wtemp			; W Sichern&lt;br /&gt;
	swapf	STATUS, w		; Status Sichern&lt;br /&gt;
	movwf	stemp			; Status Speichern&lt;br /&gt;
	btfss	PIR1, RCIF		; Interupt vom USART wenn nicht&lt;br /&gt;
	goto	intend			; Interupt beenden&lt;br /&gt;
	; Interupt Code uart&lt;br /&gt;
	call	uart_ferr		; Auf Frame Errors Testen &amp;lt;b&amp;gt;(siehe Fehlerbehandlung) &amp;lt;/b&amp;gt;&lt;br /&gt;
	call	uart_oerr		; Auf Overrunerrors Testen&lt;br /&gt;
	movf	RCREG,w			; uart RX Reg sichern&lt;br /&gt;
	movwf	rx&lt;br /&gt;
intend  ; Interupt beenden und STATUS + W zurückspielen&lt;br /&gt;
	bcf	PIR1, RCIF		; Interuptflag Löschen&lt;br /&gt;
	swapf	stemp, w		; Status restore&lt;br /&gt;
	movwf	STATUS&lt;br /&gt;
	swapf	wtemp, f		; W restore&lt;br /&gt;
	swapf	wtemp, w&lt;br /&gt;
	retfie				; Interupt Beenden&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DG-16080 Text-Mode==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrl			; LOW ADR&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrh			; High ADR&lt;br /&gt;
	call	disp_send_char		; Adressregister setzen und vorbereiten zum Daten schreiben&lt;br /&gt;
	movlw	B'01001000'		; H&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01100001'		; a&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01110101'		; u&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Display Anschlüsse:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	#define RS	PORTC, 0	; Display Command(H)/DATA(L)&lt;br /&gt;
	#define RW	PORTC, 2	; Display Read(H)/Write(L)&lt;br /&gt;
	#define E	PORTC, 3	; Display Enable&lt;br /&gt;
	#define	CS	PORTC, 4	; Display Chip Enable(L)&lt;br /&gt;
	#define	WDATA	PORTB		; Display Datenport (PORTB)&lt;br /&gt;
	#define YM	PORTA, 3	; Touch y- ADC&lt;br /&gt;
	#define YP	PORTA, 2	; Touch y+ PWR&lt;br /&gt;
	#define XP	PORTA, 4	; Touch x+ PWR&lt;br /&gt;
	#define XM	PORTA, 1	; Touch x- ADC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
dg-16080.inc&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
disp_init				; Display Inialisieren&lt;br /&gt;
	bcf	RW			; Startbedinungen herstellen&lt;br /&gt;
	nop&lt;br /&gt;
	bcf 	CS&lt;br /&gt;
	movlw	0x00			; Mode Control REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	b'00111000'		; DB5=ON/OFF, DB4=Master/Slave, DB3=Blink, DB2=Coursor, DB1/DB0=TEXT(00)/GRAFIG(10)&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x01			; Character Pitch REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x75			; 7x8px&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x02			; Nummer oh Char REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'26'			; Anzahl horit. Zeichen -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x03			; Display Duty REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x4F			; Display Duty&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x04			; Cursor Position REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'7'			; Curserstrich y-Pos -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	return&lt;br /&gt;
disp_send_c				; Send Command&lt;br /&gt;
	bsf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_send_d				; Send DATA&lt;br /&gt;
	bcf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_cls				; Display Löschen Textmode&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	D'65'&lt;br /&gt;
	movwf	count&lt;br /&gt;
disp_cls_loop&lt;br /&gt;
	movlw	B'00100000'		; 65x5&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	decfsz	count,1&lt;br /&gt;
	goto	disp_cls_loop&lt;br /&gt;
	return&lt;br /&gt;
disp_send_char				; Zeichen senden (ADRL,ADRH,Char)&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrl,w			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrh,w			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Touchscreen:&lt;br /&gt;
Config für die ADCs VREF=VDD&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	banksel	TRISA			; Zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'00001011'		; PortA I/O setzen (1=In, 0=Out) (Reinfolge RB7,RB6...)&lt;br /&gt;
	movwf	TRISA			; PortA I/O setzen&lt;br /&gt;
	banksel	ADCON1			; Zur Bank von ADCON1 umschalten&lt;br /&gt;
	movlw	B'10010100'		; Alle Analog VDD=VREF, Right jutyfy, fosc/8, AN0,1,3=AN, AN2,4-7=Dig.&lt;br /&gt;
	movwf	ADCON1			; Move w to ADCON1&lt;br /&gt;
	banksel	ADCON0			; zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'01000001'		; Enable ADC&lt;br /&gt;
	movwf	ADCON0			; Move w to ADCON0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch_read&lt;br /&gt;
	; Y&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bsf	XP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bcf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD1 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	ylow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	yhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	; X&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	bsf	YP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bsf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD3 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	xlow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	xhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	return&lt;br /&gt;
adc_read&lt;br /&gt;
	movlw	D'30'			; Wait Acquisition Time 20MHz&lt;br /&gt;
	movwf	count&lt;br /&gt;
adc_read_loop&lt;br /&gt;
	decfsz	count,F&lt;br /&gt;
	goto	adc_read_loop&lt;br /&gt;
	bsf	ADCON0,GO		; Setze ADCON0,GO, Int A/D Conversation&lt;br /&gt;
adc_read_loop_1				; Wen ADC bereit &lt;br /&gt;
	btfsc	ADCON0,GO		; Ist ADCON0,GO = 0 dann ubergehe den nesten Befehl&lt;br /&gt;
	goto	adc_read_loop_1		; Warte bis ADC fertig&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 12:00, 23. Jan 2010 (CET)&lt;br /&gt;
&lt;br /&gt;
== Schieberegister (z.b. CD4094) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; Datenleitungen Schiberegister alles Ausgänge&lt;br /&gt;
	#define		CLK		PORTB, 0&lt;br /&gt;
	#define		D	 	PORTB, 1&lt;br /&gt;
	#define		STR		PORTB, 2&lt;br /&gt;
	#define		OE		PORTB, 3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 cd4094_send&lt;br /&gt;
	banksel	PORTB&lt;br /&gt;
        bcf             OE&lt;br /&gt;
	bcf		STR&lt;br /&gt;
	btfsc	cdsend, 0&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 0&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 1&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 1&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 2&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 2&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 3&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 3&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 4&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 4&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 5&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 5&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 6&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 6&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 7&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 7&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	bsf		STR&lt;br /&gt;
        bsf             OE&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
== MAX7456 (S/W OSD) ==&lt;br /&gt;
&lt;br /&gt;
Variabeln und I/0:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	cblock	0x70		; Variabeln ab 0x70 setzen alle Register max 16stk.&lt;br /&gt;
	SPI_DATA_WRITE		; Zu Sendene SPI Daten&lt;br /&gt;
	SPI_DATA_READ		; Gelesend SPI Daten&lt;br /&gt;
	m_char			; Maxim7456 und sda5708 Zeichen&lt;br /&gt;
	m_pos			; Maxim7456 Position&lt;br /&gt;
	endc 			; Variabeln setzen beenden&lt;br /&gt;
&lt;br /&gt;
	#define	SPI_CS	PORTC, 7; SPI Slave Select max7456&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Config:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; PORTC&lt;br /&gt;
	banksel	TRISC			; auf Bank 1 umschalten&lt;br /&gt;
	movlw	B'10010000'		; PortC I/O setzen (1=In, 0=Out) (Reinfolge RC7,RC6...)&lt;br /&gt;
	movwf	TRISC			; PortC I/O setzen&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	clrf	PORTC			; PortC auf 0 setzen&lt;br /&gt;
	; SPI&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
	movlw	B'11000000'		; Mitlere Geschwindigkeit Output Time &lt;br /&gt;
	movwf	SSPSTAT&lt;br /&gt;
	banksel	SSPCON&lt;br /&gt;
	movlw	B'00100001'		; MODE 1,1, SPI MASTER, 1/16 Tosc SSP ON&lt;br /&gt;
	movwf	SSPCON&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf	SPI_CS			; SPI Slave Select aus (high)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SPI  Sende/Enfangs Rotinen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SPI_Send&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS			; Chip Select an (Low)&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SPI_DATA_WRITE, W&lt;br /&gt;
	movwf	SSPBUF&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
SPI_Wait&lt;br /&gt;
	btfss	SSPSTAT, BF		; Ist das Senden Komplet ?&lt;br /&gt;
	goto	SPI_Wait			; Wen nicht gehe zu SPIWait&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf 		SPI_CS			; Chip Select aus (High)&lt;br /&gt;
	return &lt;br /&gt;
SPI_Read&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SSPBUF, W&lt;br /&gt;
	movwf	SPI_DATA_READ&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf		SPI_CS&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Defines ASCII to MAX7456 Charset und Config und Schreibrotienen (Achtung es kann sein das die #define nicht mit mpasm Funktioniert mit gpasm wird groß und kleinschreibung unterschiden):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
max7456_define				; Defines für den max7456 Zeichensatz&lt;br /&gt;
	#define	m_sp	0x00		; Space&lt;br /&gt;
	#define	m_1		0x01&lt;br /&gt;
	#define	m_2		0x02&lt;br /&gt;
	#define	m_3		0x03&lt;br /&gt;
	#define	m_4		0x04&lt;br /&gt;
	#define	m_5		0x05&lt;br /&gt;
	#define	m_6		0x06&lt;br /&gt;
	#define	m_7		0x07&lt;br /&gt;
	#define	m_8		0x08&lt;br /&gt;
	#define	m_9		0x09&lt;br /&gt;
	#define	m_0		0x0A&lt;br /&gt;
	#define	m_A		0x0B&lt;br /&gt;
	#define	m_B		0x0C&lt;br /&gt;
	#define	m_C		0x0D&lt;br /&gt;
	#define	m_D		0x0E&lt;br /&gt;
	#define	m_E		0x0F&lt;br /&gt;
	#define	m_F		0x10&lt;br /&gt;
	#define	m_G		0x11&lt;br /&gt;
	#define	m_H		0x12&lt;br /&gt;
	#define	m_I		0x13&lt;br /&gt;
	#define	m_J		0x14&lt;br /&gt;
	#define	m_K		0x15&lt;br /&gt;
	#define	m_L		0x16&lt;br /&gt;
	#define	m_M	0x17&lt;br /&gt;
	#define	m_N		0x18&lt;br /&gt;
	#define	m_O		0x19&lt;br /&gt;
	#define	m_P		0x1A&lt;br /&gt;
	#define	m_Q		0x1B&lt;br /&gt;
	#define	m_R		0x1C&lt;br /&gt;
	#define	m_S		0x1D&lt;br /&gt;
	#define	m_T		0x1E&lt;br /&gt;
	#define	m_U		0x1F&lt;br /&gt;
	#define	m_V		0x20&lt;br /&gt;
	#define	m_W	0x21&lt;br /&gt;
	#define	m_X		0x22&lt;br /&gt;
	#define	m_Y		0x23&lt;br /&gt;
	#define	m_Z		0x24&lt;br /&gt;
	#define	m_a		0x25&lt;br /&gt;
	#define	m_b		0x26&lt;br /&gt;
	#define	m_c		0x27&lt;br /&gt;
	#define	m_d		0x28&lt;br /&gt;
	#define	m_e		0x29&lt;br /&gt;
	#define	m_f		0x2A&lt;br /&gt;
	#define	m_g		0x2B&lt;br /&gt;
	#define	m_h		0x2C&lt;br /&gt;
	#define	m_i		0x2D&lt;br /&gt;
	#define	m_j		0x2E&lt;br /&gt;
	#define	m_k		0x2F&lt;br /&gt;
	#define	m_l		0x30&lt;br /&gt;
	#define	m_m		0x31&lt;br /&gt;
	#define	m_n		0x32&lt;br /&gt;
	#define	m_o		0x33&lt;br /&gt;
	#define	m_p		0x34&lt;br /&gt;
	#define	m_q		0x35&lt;br /&gt;
	#define	m_r		0x36&lt;br /&gt;
	#define	m_s		0x37&lt;br /&gt;
	#define	m_t		0x38&lt;br /&gt;
	#define	m_u		0x39&lt;br /&gt;
	#define	m_v		0x3A&lt;br /&gt;
	#define	m_w		0x3B&lt;br /&gt;
	#define	m_x		0x3C&lt;br /&gt;
	#define	m_y		0x3D&lt;br /&gt;
	#define	m_z		0x3E&lt;br /&gt;
	#define	m_KLa	0x3F	; (&lt;br /&gt;
	#define	m_KLz	0x40		; )&lt;br /&gt;
	#define	m_.		0x41&lt;br /&gt;
	#define	m_?		0x42&lt;br /&gt;
	#define	m_sem	0x43		; ;&lt;br /&gt;
	#define	m_:		0x44&lt;br /&gt;
	#define	m_ko	0x45		; ,&lt;br /&gt;
	#define	m_ag	0x46		; Agostroff&lt;br /&gt;
	#define	m_bs	0x47		; Backslasch&lt;br /&gt;
	#define	m_as	0x48		; Anfürungsstriche&lt;br /&gt;
	#define	m_minus  0x49		; Minus&lt;br /&gt;
	#define	m_ka	0x4A		; &amp;lt;&lt;br /&gt;
	#define	m_ga	0x4B	; &amp;gt;&lt;br /&gt;
	#define	m_at	0x4C	; @ oder at&lt;br /&gt;
	#define	m_wait	0xfb		; Wartezeichen&lt;br /&gt;
	#define	m_ls		0xf9		; Lautsprecher&lt;br /&gt;
	#define	m_lso	0xfa		; Tonsignal&lt;br /&gt;
	#define	m_ff		0xff		; Ausgefültes feld&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_conf					; Max7456 Config&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001000'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 0=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x01				; VM1 Video Mode Register 1&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00000100'		; 0 = NA, 000=Background MODE Brightness 100%, 11=Blinking Time 160ms, 00=Blinking Duty Cycle BT:BT&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x02				; HOS Horizontal Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00101111'		; 00 = NA, 100000 = Horitzontal Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x03				; VOS Vertical Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00010111'		; 000 = NA, 10000 = Vertical Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_cls					; max7456 ausgabe Löschen&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001010'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 1=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	call		max7456_conf&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_high				; High adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 0x00, Letzten 256 Zeichen High=0xff &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0xFF&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_low				; Low Adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 000, Letzten 256 Zeichen High=225 &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_send_char&lt;br /&gt;
	movlw	0x06				; Zeichen Position links nach rechts erste reihe 0-29, 30-......&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_pos, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x07				; Zeichen Sonderzeichen sihe Define in max7456.inc&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_char, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeichen Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	D'12'			; Position&lt;br /&gt;
	movwf	m_pos&lt;br /&gt;
	movlw	m_e			; Zeichen (hier das kleine e) oder direkt den wert des Zeichens im MAX7456 REG.&lt;br /&gt;
	movwf	m_char&lt;br /&gt;
	call	max7456_send_char; Schreiben&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
High/low Adressbereich (low = ersten 256 Zeichen, High die letzten 128 Zeichen);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	call		max7456_add_low	; Low Adressbereich&lt;br /&gt;
	;call		max7456_add_high; Low Adressbereich&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
= PIC18... =&lt;br /&gt;
&lt;br /&gt;
== Programmspeicher (Flash) beschreiben und lesen ==&lt;br /&gt;
&lt;br /&gt;
Zuerst wird der benötigte Flash-Bereich gelöscht und danach werden dort Daten aus RAM kopiert (gespeichert). Dazu wurden zwei Register &amp;quot;Tmp&amp;quot; und &amp;quot;Tmp1&amp;quot; benutzt, die im Program definiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
 Store		movff	F2,FS2&lt;br /&gt;
 		movff	F1,FS1&lt;br /&gt;
 		movff	F0,FS0&lt;br /&gt;
 		clrf	TBLPTRU			; erase flash memory (7BC0-7FFF)&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		movlw	0x11&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 FlashEraseL	bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bsf	EECON1,FREE&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		bra	$-2&lt;br /&gt;
 		movlw	0x40&lt;br /&gt;
 		addwf	TBLPTRL&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		incf	TBLPTRH,1&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	FlashEraseL&lt;br /&gt;
 		lfsr	FSR0,0x0020		; write parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	4&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgPL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFPL	movff	POSTINC0,TABLAT&lt;br /&gt;
 		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFPL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgPL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 WriteSMP	lfsr	FSR0,0x100		; write samples 1024 bytes (7C00-7FFF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFL		movff	POSTINC0,TABLAT&lt;br /&gt;
  		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Um die Daten aus Flash zurück auf ursprüngliche Adressen im RAM zu übertragen, wurde folgendes Programmfragment verwendet in dem Register &amp;quot;STmp&amp;quot; benutzt wurde, der auch im Programm definiert werden muss.&lt;br /&gt;
&lt;br /&gt;
 Restore		lfsr	FSR0,0x0020		; restore parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 FlashRAMP	movlw	0x20&lt;br /&gt;
 		movwf	STmp&lt;br /&gt;
 FlashRAMPL	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAMPL&lt;br /&gt;
 		lfsr	FSR0,0x100		; restore samples 1024 bytes (7C00-7FFF)	&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 FlashRAM	clrf	STmp&lt;br /&gt;
 FlashRAML	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAML&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
== Hex Dec Wandlung ==&lt;br /&gt;
&lt;br /&gt;
Weil das UP mit PAD erstellt wurde, ist es fast nicht kommentiert. Genaue Funktionsweise und Definitionen der Register sind im http://www.rn-wissen.de/index.php/PIC_Assembler#Hex_Dec_Wandlung beschrieben.&lt;br /&gt;
&lt;br /&gt;
Übrigens, das UP wurde ursprünglich für PIC18... erstellt und danach auf PIC12.. und PIC16... umgeschrieben. Durchs Vergleichen sieht man den Unterschied zwischen den PIC Familien.&lt;br /&gt;
&lt;br /&gt;
 Hex_Dec		call	CClr			; Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		call	DClr&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x18			; 24 bit Hex (6 Ziffer) &amp;gt; 32 bit Dec (8 Ziffer)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 Hex_DecL	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		bra	Hex_DecL&lt;br /&gt;
 		return&lt;br /&gt;
 CClr		lfsr	FSR0,C4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		bra	RegClr&lt;br /&gt;
 DClr		lfsr	FSR0,D4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 RegClr		movwf	ATmp&lt;br /&gt;
 RegClrL		clrf	POSTINC0&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	RegClrL&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		lfsr	FSR0,C0&lt;br /&gt;
 		lfsr	FSR1,B0&lt;br /&gt;
 CopyReg		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 CopyRegL	movff	POSTDEC0,POSTDEC1       ; INDF0 in INDF1 kopieren und Zeiger dekrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	CopyRegL		&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		lfsr	FSR0,B0			; C+B&amp;gt;C&lt;br /&gt;
 		lfsr	FSR1,C0&lt;br /&gt;
 		bra	AddReg&lt;br /&gt;
 AddDC		lfsr	FSR0,C0			; D+C&amp;gt;D&lt;br /&gt;
 		lfsr	FSR1,D0&lt;br /&gt;
 AddReg		bcf	_Ferr&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRegL		bcf	_Fcra&lt;br /&gt;
 		movf	INDF0,0&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		bra	AddRegN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddRegN		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTDEC0,1              ; Zeiger für INDF0 um 1 dekrementieren&lt;br /&gt;
 		movf	POSTDEC1,1              ; Zeiger für INDF1 um 1 decrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	AddRegL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		lfsr	FSR0,A2	&lt;br /&gt;
 RRotRb		movlw	3			; A Rregister um 1 bit nach rechts rotieren&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL		bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF0,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrcf	INDF0,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTINC0,1              ; Zeiger für INDF0 um 1 inkrementieren             &lt;br /&gt;
 		decfsz	RTmp,1&lt;br /&gt;
 		bra	RRotRbL&lt;br /&gt;
 		return &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16885</id>
		<title>PIC ASM Beispiele</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16885"/>
				<updated>2010-08-15T11:10:46Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* PIC18(F/LF)xxxx */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PIC12...&amp;amp; PIC16... =&lt;br /&gt;
&lt;br /&gt;
Einige ASM Beispiele für PC12... und PIC16... befinden sich in http://www.rn-wissen.de/index.php/PIC_Assembler#Codeschnipsel .&lt;br /&gt;
&lt;br /&gt;
== UART Routine ==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RS232send&lt;br /&gt;
	banksel  	TXREG			; Zur Bank von TXREG umschalten&lt;br /&gt;
	movwf	        TXREG			; Move w to TXREG &lt;br /&gt;
	banksel	        PIR1			; Zur Bank von PIR1 umschalten&lt;br /&gt;
Waittx	&lt;br /&gt;
	btfss		PIR1, TXIF		; Wenn bit in PIR1,TXIF HIGH übergehe den nästen Befehl&lt;br /&gt;
	goto		Waittx			; Gehe zu WaitTX&lt;br /&gt;
	bcf		PIR1, TXIF 		; Interrupt Flag Löschen (Optionam muss nicht umbedinkt gemacht werden)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlerbehandlung:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
uart_ferr				; Auf Frameerror testen&lt;br /&gt;
	btfsc	RCSTA, FERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_oerr				; Auf Overrunerror testen&lt;br /&gt;
	btfsc	RCSTA, OERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_err				; Fehlerbehandlung&lt;br /&gt;
	; Fehlerbehanlungsroutine hier einfügen!!!!!!!!!!!!!!!!!&lt;br /&gt;
        ; z.b. Interupt beenden und RCREG nicht sichern&lt;br /&gt;
	bcf	RCSTA, CREN		; Fehler Bits Löschen&lt;br /&gt;
	bsf	RCSTA, CREN&lt;br /&gt;
	return				; Interupt beenden und zurück zur Main schleife&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Entfangen per Interupt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int	; Interupt STATUS und W sichern&lt;br /&gt;
	movwf	wtemp			; W Sichern&lt;br /&gt;
	swapf	STATUS, w		; Status Sichern&lt;br /&gt;
	movwf	stemp			; Status Speichern&lt;br /&gt;
	btfss	PIR1, RCIF		; Interupt vom USART wenn nicht&lt;br /&gt;
	goto	intend			; Interupt beenden&lt;br /&gt;
	; Interupt Code uart&lt;br /&gt;
	call	uart_ferr		; Auf Frame Errors Testen &amp;lt;b&amp;gt;(siehe Fehlerbehandlung) &amp;lt;/b&amp;gt;&lt;br /&gt;
	call	uart_oerr		; Auf Overrunerrors Testen&lt;br /&gt;
	movf	RCREG,w			; uart RX Reg sichern&lt;br /&gt;
	movwf	rx&lt;br /&gt;
intend  ; Interupt beenden und STATUS + W zurückspielen&lt;br /&gt;
	bcf	PIR1, RCIF		; Interuptflag Löschen&lt;br /&gt;
	swapf	stemp, w		; Status restore&lt;br /&gt;
	movwf	STATUS&lt;br /&gt;
	swapf	wtemp, f		; W restore&lt;br /&gt;
	swapf	wtemp, w&lt;br /&gt;
	retfie				; Interupt Beenden&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DG-16080 Text-Mode==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrl			; LOW ADR&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrh			; High ADR&lt;br /&gt;
	call	disp_send_char		; Adressregister setzen und vorbereiten zum Daten schreiben&lt;br /&gt;
	movlw	B'01001000'		; H&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01100001'		; a&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01110101'		; u&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Display Anschlüsse:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	#define RS	PORTC, 0	; Display Command(H)/DATA(L)&lt;br /&gt;
	#define RW	PORTC, 2	; Display Read(H)/Write(L)&lt;br /&gt;
	#define E	PORTC, 3	; Display Enable&lt;br /&gt;
	#define	CS	PORTC, 4	; Display Chip Enable(L)&lt;br /&gt;
	#define	WDATA	PORTB		; Display Datenport (PORTB)&lt;br /&gt;
	#define YM	PORTA, 3	; Touch y- ADC&lt;br /&gt;
	#define YP	PORTA, 2	; Touch y+ PWR&lt;br /&gt;
	#define XP	PORTA, 4	; Touch x+ PWR&lt;br /&gt;
	#define XM	PORTA, 1	; Touch x- ADC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
dg-16080.inc&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
disp_init				; Display Inialisieren&lt;br /&gt;
	bcf	RW			; Startbedinungen herstellen&lt;br /&gt;
	nop&lt;br /&gt;
	bcf 	CS&lt;br /&gt;
	movlw	0x00			; Mode Control REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	b'00111000'		; DB5=ON/OFF, DB4=Master/Slave, DB3=Blink, DB2=Coursor, DB1/DB0=TEXT(00)/GRAFIG(10)&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x01			; Character Pitch REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x75			; 7x8px&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x02			; Nummer oh Char REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'26'			; Anzahl horit. Zeichen -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x03			; Display Duty REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x4F			; Display Duty&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x04			; Cursor Position REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'7'			; Curserstrich y-Pos -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	return&lt;br /&gt;
disp_send_c				; Send Command&lt;br /&gt;
	bsf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_send_d				; Send DATA&lt;br /&gt;
	bcf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_cls				; Display Löschen Textmode&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	D'65'&lt;br /&gt;
	movwf	count&lt;br /&gt;
disp_cls_loop&lt;br /&gt;
	movlw	B'00100000'		; 65x5&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	decfsz	count,1&lt;br /&gt;
	goto	disp_cls_loop&lt;br /&gt;
	return&lt;br /&gt;
disp_send_char				; Zeichen senden (ADRL,ADRH,Char)&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrl,w			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrh,w			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Touchscreen:&lt;br /&gt;
Config für die ADCs VREF=VDD&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	banksel	TRISA			; Zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'00001011'		; PortA I/O setzen (1=In, 0=Out) (Reinfolge RB7,RB6...)&lt;br /&gt;
	movwf	TRISA			; PortA I/O setzen&lt;br /&gt;
	banksel	ADCON1			; Zur Bank von ADCON1 umschalten&lt;br /&gt;
	movlw	B'10010100'		; Alle Analog VDD=VREF, Right jutyfy, fosc/8, AN0,1,3=AN, AN2,4-7=Dig.&lt;br /&gt;
	movwf	ADCON1			; Move w to ADCON1&lt;br /&gt;
	banksel	ADCON0			; zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'01000001'		; Enable ADC&lt;br /&gt;
	movwf	ADCON0			; Move w to ADCON0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch_read&lt;br /&gt;
	; Y&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bsf	XP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bcf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD1 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	ylow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	yhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	; X&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	bsf	YP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bsf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD3 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	xlow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	xhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	return&lt;br /&gt;
adc_read&lt;br /&gt;
	movlw	D'30'			; Wait Acquisition Time 20MHz&lt;br /&gt;
	movwf	count&lt;br /&gt;
adc_read_loop&lt;br /&gt;
	decfsz	count,F&lt;br /&gt;
	goto	adc_read_loop&lt;br /&gt;
	bsf	ADCON0,GO		; Setze ADCON0,GO, Int A/D Conversation&lt;br /&gt;
adc_read_loop_1				; Wen ADC bereit &lt;br /&gt;
	btfsc	ADCON0,GO		; Ist ADCON0,GO = 0 dann ubergehe den nesten Befehl&lt;br /&gt;
	goto	adc_read_loop_1		; Warte bis ADC fertig&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 12:00, 23. Jan 2010 (CET)&lt;br /&gt;
&lt;br /&gt;
== Schieberegister (z.b. CD4094) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; Datenleitungen Schiberegister alles Ausgänge&lt;br /&gt;
	#define		CLK		PORTB, 0&lt;br /&gt;
	#define		D	 	PORTB, 1&lt;br /&gt;
	#define		STR		PORTB, 2&lt;br /&gt;
	#define		OE		PORTB, 3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 cd4094_send&lt;br /&gt;
	banksel	PORTB&lt;br /&gt;
        bcf             OE&lt;br /&gt;
	bcf		STR&lt;br /&gt;
	btfsc	cdsend, 0&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 0&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 1&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 1&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 2&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 2&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 3&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 3&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 4&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 4&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 5&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 5&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 6&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 6&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 7&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 7&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	bsf		STR&lt;br /&gt;
        bsf             OE&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
== MAX7456 (S/W OSD) ==&lt;br /&gt;
&lt;br /&gt;
Variabeln und I/0:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	cblock	0x70		; Variabeln ab 0x70 setzen alle Register max 16stk.&lt;br /&gt;
	SPI_DATA_WRITE		; Zu Sendene SPI Daten&lt;br /&gt;
	SPI_DATA_READ		; Gelesend SPI Daten&lt;br /&gt;
	m_char			; Maxim7456 und sda5708 Zeichen&lt;br /&gt;
	m_pos			; Maxim7456 Position&lt;br /&gt;
	endc 			; Variabeln setzen beenden&lt;br /&gt;
&lt;br /&gt;
	#define	SPI_CS	PORTC, 7; SPI Slave Select max7456&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Config:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; PORTC&lt;br /&gt;
	banksel	TRISC			; auf Bank 1 umschalten&lt;br /&gt;
	movlw	B'10010000'		; PortC I/O setzen (1=In, 0=Out) (Reinfolge RC7,RC6...)&lt;br /&gt;
	movwf	TRISC			; PortC I/O setzen&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	clrf	PORTC			; PortC auf 0 setzen&lt;br /&gt;
	; SPI&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
	movlw	B'11000000'		; Mitlere Geschwindigkeit Output Time &lt;br /&gt;
	movwf	SSPSTAT&lt;br /&gt;
	banksel	SSPCON&lt;br /&gt;
	movlw	B'00100001'		; MODE 1,1, SPI MASTER, 1/16 Tosc SSP ON&lt;br /&gt;
	movwf	SSPCON&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf	SPI_CS			; SPI Slave Select aus (high)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SPI  Sende/Enfangs Rotinen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SPI_Send&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS			; Chip Select an (Low)&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SPI_DATA_WRITE, W&lt;br /&gt;
	movwf	SSPBUF&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
SPI_Wait&lt;br /&gt;
	btfss	SSPSTAT, BF		; Ist das Senden Komplet ?&lt;br /&gt;
	goto	SPI_Wait			; Wen nicht gehe zu SPIWait&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf 		SPI_CS			; Chip Select aus (High)&lt;br /&gt;
	return &lt;br /&gt;
SPI_Read&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SSPBUF, W&lt;br /&gt;
	movwf	SPI_DATA_READ&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf		SPI_CS&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Defines ASCII to MAX7456 Charset und Config und Schreibrotienen (Achtung es kann sein das die #define nicht mit mpasm Funktioniert mit gpasm wird groß und kleinschreibung unterschiden):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
max7456_define				; Defines für den max7456 Zeichensatz&lt;br /&gt;
	#define	m_sp	0x00		; Space&lt;br /&gt;
	#define	m_1		0x01&lt;br /&gt;
	#define	m_2		0x02&lt;br /&gt;
	#define	m_3		0x03&lt;br /&gt;
	#define	m_4		0x04&lt;br /&gt;
	#define	m_5		0x05&lt;br /&gt;
	#define	m_6		0x06&lt;br /&gt;
	#define	m_7		0x07&lt;br /&gt;
	#define	m_8		0x08&lt;br /&gt;
	#define	m_9		0x09&lt;br /&gt;
	#define	m_0		0x0A&lt;br /&gt;
	#define	m_A		0x0B&lt;br /&gt;
	#define	m_B		0x0C&lt;br /&gt;
	#define	m_C		0x0D&lt;br /&gt;
	#define	m_D		0x0E&lt;br /&gt;
	#define	m_E		0x0F&lt;br /&gt;
	#define	m_F		0x10&lt;br /&gt;
	#define	m_G		0x11&lt;br /&gt;
	#define	m_H		0x12&lt;br /&gt;
	#define	m_I		0x13&lt;br /&gt;
	#define	m_J		0x14&lt;br /&gt;
	#define	m_K		0x15&lt;br /&gt;
	#define	m_L		0x16&lt;br /&gt;
	#define	m_M	0x17&lt;br /&gt;
	#define	m_N		0x18&lt;br /&gt;
	#define	m_O		0x19&lt;br /&gt;
	#define	m_P		0x1A&lt;br /&gt;
	#define	m_Q		0x1B&lt;br /&gt;
	#define	m_R		0x1C&lt;br /&gt;
	#define	m_S		0x1D&lt;br /&gt;
	#define	m_T		0x1E&lt;br /&gt;
	#define	m_U		0x1F&lt;br /&gt;
	#define	m_V		0x20&lt;br /&gt;
	#define	m_W	0x21&lt;br /&gt;
	#define	m_X		0x22&lt;br /&gt;
	#define	m_Y		0x23&lt;br /&gt;
	#define	m_Z		0x24&lt;br /&gt;
	#define	m_a		0x25&lt;br /&gt;
	#define	m_b		0x26&lt;br /&gt;
	#define	m_c		0x27&lt;br /&gt;
	#define	m_d		0x28&lt;br /&gt;
	#define	m_e		0x29&lt;br /&gt;
	#define	m_f		0x2A&lt;br /&gt;
	#define	m_g		0x2B&lt;br /&gt;
	#define	m_h		0x2C&lt;br /&gt;
	#define	m_i		0x2D&lt;br /&gt;
	#define	m_j		0x2E&lt;br /&gt;
	#define	m_k		0x2F&lt;br /&gt;
	#define	m_l		0x30&lt;br /&gt;
	#define	m_m		0x31&lt;br /&gt;
	#define	m_n		0x32&lt;br /&gt;
	#define	m_o		0x33&lt;br /&gt;
	#define	m_p		0x34&lt;br /&gt;
	#define	m_q		0x35&lt;br /&gt;
	#define	m_r		0x36&lt;br /&gt;
	#define	m_s		0x37&lt;br /&gt;
	#define	m_t		0x38&lt;br /&gt;
	#define	m_u		0x39&lt;br /&gt;
	#define	m_v		0x3A&lt;br /&gt;
	#define	m_w		0x3B&lt;br /&gt;
	#define	m_x		0x3C&lt;br /&gt;
	#define	m_y		0x3D&lt;br /&gt;
	#define	m_z		0x3E&lt;br /&gt;
	#define	m_KLa	0x3F	; (&lt;br /&gt;
	#define	m_KLz	0x40		; )&lt;br /&gt;
	#define	m_.		0x41&lt;br /&gt;
	#define	m_?		0x42&lt;br /&gt;
	#define	m_sem	0x43		; ;&lt;br /&gt;
	#define	m_:		0x44&lt;br /&gt;
	#define	m_ko	0x45		; ,&lt;br /&gt;
	#define	m_ag	0x46		; Agostroff&lt;br /&gt;
	#define	m_bs	0x47		; Backslasch&lt;br /&gt;
	#define	m_as	0x48		; Anfürungsstriche&lt;br /&gt;
	#define	m_minus  0x49		; Minus&lt;br /&gt;
	#define	m_ka	0x4A		; &amp;lt;&lt;br /&gt;
	#define	m_ga	0x4B	; &amp;gt;&lt;br /&gt;
	#define	m_at	0x4C	; @ oder at&lt;br /&gt;
	#define	m_wait	0xfb		; Wartezeichen&lt;br /&gt;
	#define	m_ls		0xf9		; Lautsprecher&lt;br /&gt;
	#define	m_lso	0xfa		; Tonsignal&lt;br /&gt;
	#define	m_ff		0xff		; Ausgefültes feld&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_conf					; Max7456 Config&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001000'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 0=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x01				; VM1 Video Mode Register 1&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00000100'		; 0 = NA, 000=Background MODE Brightness 100%, 11=Blinking Time 160ms, 00=Blinking Duty Cycle BT:BT&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x02				; HOS Horizontal Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00101111'		; 00 = NA, 100000 = Horitzontal Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x03				; VOS Vertical Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00010111'		; 000 = NA, 10000 = Vertical Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_cls					; max7456 ausgabe Löschen&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001010'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 1=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	call		max7456_conf&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_high				; High adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 0x00, Letzten 256 Zeichen High=0xff &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0xFF&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_low				; Low Adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 000, Letzten 256 Zeichen High=225 &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_send_char&lt;br /&gt;
	movlw	0x06				; Zeichen Position links nach rechts erste reihe 0-29, 30-......&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_pos, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x07				; Zeichen Sonderzeichen sihe Define in max7456.inc&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_char, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeichen Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	D'12'			; Position&lt;br /&gt;
	movwf	m_pos&lt;br /&gt;
	movlw	m_e			; Zeichen (hier das kleine e) oder direkt den wert des Zeichens im MAX7456 REG.&lt;br /&gt;
	movwf	m_char&lt;br /&gt;
	call	max7456_send_char; Schreiben&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
High/low Adressbereich (low = ersten 256 Zeichen, High die letzten 128 Zeichen);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	call		max7456_add_low	; Low Adressbereich&lt;br /&gt;
	;call		max7456_add_high; Low Adressbereich&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
= PIC18... =&lt;br /&gt;
&lt;br /&gt;
== Programmspeicher (Flash) beschreiben und lesen ==&lt;br /&gt;
&lt;br /&gt;
Weil das Programteil mit PAD erstellt wurde, ist fast nicht kommentiert. Zuerst wird der benötigte Flash-Bereich gelöscht und danach werden dort Daten aus RAM kopiert (gespeichert). Dazu wurden zwei Register &amp;quot;Tmp&amp;quot; und &amp;quot;Tmp1&amp;quot; benutzt, die im Program definiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
 Store		movff	F2,FS2&lt;br /&gt;
 		movff	F1,FS1&lt;br /&gt;
 		movff	F0,FS0&lt;br /&gt;
 		clrf	TBLPTRU			; erase flash memory (7BC0-7FFF)&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		movlw	0x11&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 FlashEraseL	bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bsf	EECON1,FREE&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		bra	$-2&lt;br /&gt;
 		movlw	0x40&lt;br /&gt;
 		addwf	TBLPTRL&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		incf	TBLPTRH,1&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	FlashEraseL&lt;br /&gt;
 		lfsr	FSR0,0x0020		; write parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	4&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgPL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFPL	movff	POSTINC0,TABLAT&lt;br /&gt;
 		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFPL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgPL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 WriteSMP	lfsr	FSR0,0x100		; write samples 1024 bytes (7C00-7FFF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFL		movff	POSTINC0,TABLAT&lt;br /&gt;
  		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Um die Daten aus Flash zurück auf ursprüngliche Adressen im RAM zu übertragen, wurde folgendes Programmfragment verwendet in dem Register &amp;quot;STmp&amp;quot; benutzt wurde, der auch im Programm definiert werden muss.&lt;br /&gt;
&lt;br /&gt;
 Restore		lfsr	FSR0,0x0020		; restore parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 FlashRAMP	movlw	0x20&lt;br /&gt;
 		movwf	STmp&lt;br /&gt;
 FlashRAMPL	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAMPL&lt;br /&gt;
 		lfsr	FSR0,0x100		; restore samples 1024 bytes (7C00-7FFF)	&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 FlashRAM	clrf	STmp&lt;br /&gt;
 FlashRAML	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAML&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
== Hex Dec Wandlung ==&lt;br /&gt;
&lt;br /&gt;
Weil das UP mit PAD erstellt wurde, ist es fast nicht kommentiert. Genaue Funktionsweise und Definitionen der Register sind im http://www.rn-wissen.de/index.php/PIC_Assembler#Hex_Dec_Wandlung beschrieben.&lt;br /&gt;
&lt;br /&gt;
Übrigens, das UP wurde ursprünglich für PIC18... erstellt und danach auf PIC12.. und PIC16... umgeschrieben. Durchs Vergleichen sieht man den Unterschied zwischen den PIC Familien.&lt;br /&gt;
&lt;br /&gt;
 Hex_Dec		call	CClr			; Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		call	DClr&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x18			; 24 bit Hex (6 Ziffer) &amp;gt; 32 bit Dec (8 Ziffer)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 Hex_DecL	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		bra	Hex_DecL&lt;br /&gt;
 		return&lt;br /&gt;
 CClr		lfsr	FSR0,C4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		bra	RegClr&lt;br /&gt;
 DClr		lfsr	FSR0,D4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 RegClr		movwf	ATmp&lt;br /&gt;
 RegClrL		clrf	POSTINC0&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	RegClrL&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		lfsr	FSR0,C0&lt;br /&gt;
 		lfsr	FSR1,B0&lt;br /&gt;
 CopyReg		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 CopyRegL	movff	POSTDEC0,POSTDEC1       ; INDF0 in INDF1 kopieren und Zeiger dekrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	CopyRegL		&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		lfsr	FSR0,B0			; C+B&amp;gt;C&lt;br /&gt;
 		lfsr	FSR1,C0&lt;br /&gt;
 		bra	AddReg&lt;br /&gt;
 AddDC		lfsr	FSR0,C0			; D+C&amp;gt;D&lt;br /&gt;
 		lfsr	FSR1,D0&lt;br /&gt;
 AddReg		bcf	_Ferr&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRegL		bcf	_Fcra&lt;br /&gt;
 		movf	INDF0,0&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		bra	AddRegN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddRegN		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTDEC0,1              ; Zeiger für INDF0 um 1 dekrementieren&lt;br /&gt;
 		movf	POSTDEC1,1              ; Zeiger für INDF1 um 1 decrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	AddRegL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		lfsr	FSR0,A2	&lt;br /&gt;
 RRotRb		movlw	3			; A Rregister um 1 bit nach rechts rotieren&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL		bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF0,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrcf	INDF0,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTINC0,1              ; Zeiger für INDF0 um 1 inkrementieren             &lt;br /&gt;
 		decfsz	RTmp,1&lt;br /&gt;
 		bra	RRotRbL&lt;br /&gt;
 		return &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16884</id>
		<title>PIC ASM Beispiele</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_ASM_Beispiele&amp;diff=16884"/>
				<updated>2010-08-15T11:09:55Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* PIC16(F/LF)XXX */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= PIC12...&amp;amp; PIC16... =&lt;br /&gt;
&lt;br /&gt;
Einige ASM Beispiele für PC12... und PIC16... befinden sich in http://www.rn-wissen.de/index.php/PIC_Assembler#Codeschnipsel .&lt;br /&gt;
&lt;br /&gt;
== UART Routine ==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RS232send&lt;br /&gt;
	banksel  	TXREG			; Zur Bank von TXREG umschalten&lt;br /&gt;
	movwf	        TXREG			; Move w to TXREG &lt;br /&gt;
	banksel	        PIR1			; Zur Bank von PIR1 umschalten&lt;br /&gt;
Waittx	&lt;br /&gt;
	btfss		PIR1, TXIF		; Wenn bit in PIR1,TXIF HIGH übergehe den nästen Befehl&lt;br /&gt;
	goto		Waittx			; Gehe zu WaitTX&lt;br /&gt;
	bcf		PIR1, TXIF 		; Interrupt Flag Löschen (Optionam muss nicht umbedinkt gemacht werden)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fehlerbehandlung:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
uart_ferr				; Auf Frameerror testen&lt;br /&gt;
	btfsc	RCSTA, FERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_oerr				; Auf Overrunerror testen&lt;br /&gt;
	btfsc	RCSTA, OERR&lt;br /&gt;
	goto	uart_err&lt;br /&gt;
	return&lt;br /&gt;
uart_err				; Fehlerbehandlung&lt;br /&gt;
	; Fehlerbehanlungsroutine hier einfügen!!!!!!!!!!!!!!!!!&lt;br /&gt;
        ; z.b. Interupt beenden und RCREG nicht sichern&lt;br /&gt;
	bcf	RCSTA, CREN		; Fehler Bits Löschen&lt;br /&gt;
	bsf	RCSTA, CREN&lt;br /&gt;
	return				; Interupt beenden und zurück zur Main schleife&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Entfangen per Interupt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
int	; Interupt STATUS und W sichern&lt;br /&gt;
	movwf	wtemp			; W Sichern&lt;br /&gt;
	swapf	STATUS, w		; Status Sichern&lt;br /&gt;
	movwf	stemp			; Status Speichern&lt;br /&gt;
	btfss	PIR1, RCIF		; Interupt vom USART wenn nicht&lt;br /&gt;
	goto	intend			; Interupt beenden&lt;br /&gt;
	; Interupt Code uart&lt;br /&gt;
	call	uart_ferr		; Auf Frame Errors Testen &amp;lt;b&amp;gt;(siehe Fehlerbehandlung) &amp;lt;/b&amp;gt;&lt;br /&gt;
	call	uart_oerr		; Auf Overrunerrors Testen&lt;br /&gt;
	movf	RCREG,w			; uart RX Reg sichern&lt;br /&gt;
	movwf	rx&lt;br /&gt;
intend  ; Interupt beenden und STATUS + W zurückspielen&lt;br /&gt;
	bcf	PIR1, RCIF		; Interuptflag Löschen&lt;br /&gt;
	swapf	stemp, w		; Status restore&lt;br /&gt;
	movwf	STATUS&lt;br /&gt;
	swapf	wtemp, f		; W restore&lt;br /&gt;
	swapf	wtemp, w&lt;br /&gt;
	retfie				; Interupt Beenden&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DG-16080 Text-Mode==&lt;br /&gt;
&lt;br /&gt;
Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrl			; LOW ADR&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	adrh			; High ADR&lt;br /&gt;
	call	disp_send_char		; Adressregister setzen und vorbereiten zum Daten schreiben&lt;br /&gt;
	movlw	B'01001000'		; H&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01100001'		; a&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	B'01110101'		; u&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Display Anschlüsse:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	#define RS	PORTC, 0	; Display Command(H)/DATA(L)&lt;br /&gt;
	#define RW	PORTC, 2	; Display Read(H)/Write(L)&lt;br /&gt;
	#define E	PORTC, 3	; Display Enable&lt;br /&gt;
	#define	CS	PORTC, 4	; Display Chip Enable(L)&lt;br /&gt;
	#define	WDATA	PORTB		; Display Datenport (PORTB)&lt;br /&gt;
	#define YM	PORTA, 3	; Touch y- ADC&lt;br /&gt;
	#define YP	PORTA, 2	; Touch y+ PWR&lt;br /&gt;
	#define XP	PORTA, 4	; Touch x+ PWR&lt;br /&gt;
	#define XM	PORTA, 1	; Touch x- ADC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
dg-16080.inc&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
disp_init				; Display Inialisieren&lt;br /&gt;
	bcf	RW			; Startbedinungen herstellen&lt;br /&gt;
	nop&lt;br /&gt;
	bcf 	CS&lt;br /&gt;
	movlw	0x00			; Mode Control REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	b'00111000'		; DB5=ON/OFF, DB4=Master/Slave, DB3=Blink, DB2=Coursor, DB1/DB0=TEXT(00)/GRAFIG(10)&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x01			; Character Pitch REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x75			; 7x8px&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x02			; Nummer oh Char REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'26'			; Anzahl horit. Zeichen -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x03			; Display Duty REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	0x4F			; Display Duty&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	movlw	0x04			; Cursor Position REG&lt;br /&gt;
	call	disp_send_c		; Send Command&lt;br /&gt;
	movlw	D'7'			; Curserstrich y-Pos -1&lt;br /&gt;
	call	disp_send_d		; Send Data&lt;br /&gt;
	return&lt;br /&gt;
disp_send_c				; Send Command&lt;br /&gt;
	bsf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_send_d				; Send DATA&lt;br /&gt;
	bcf	RS&lt;br /&gt;
	movwf	WDATA&lt;br /&gt;
	bsf	E&lt;br /&gt;
	nop&lt;br /&gt;
	bcf	E&lt;br /&gt;
	call	delay_10_µs&lt;br /&gt;
	return&lt;br /&gt;
disp_cls				; Display Löschen Textmode&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	0x00			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movlw	D'65'&lt;br /&gt;
	movwf	count&lt;br /&gt;
disp_cls_loop&lt;br /&gt;
	movlw	B'00100000'		; 65x5&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	decfsz	count,1&lt;br /&gt;
	goto	disp_cls_loop&lt;br /&gt;
	return&lt;br /&gt;
disp_send_char				; Zeichen senden (ADRL,ADRH,Char)&lt;br /&gt;
	movlw	0x0A			; Low Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrl,w			; Low Adr&lt;br /&gt;
	call	disp_send_d&lt;br /&gt;
	movlw	0x0B 			; High Reg&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	movf	adrh,w			; High Adr&lt;br /&gt;
	call	disp_send_d &lt;br /&gt;
	movlw	0x0C			; DATA REG&lt;br /&gt;
	call	disp_send_c&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Touchscreen:&lt;br /&gt;
Config für die ADCs VREF=VDD&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	banksel	TRISA			; Zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'00001011'		; PortA I/O setzen (1=In, 0=Out) (Reinfolge RB7,RB6...)&lt;br /&gt;
	movwf	TRISA			; PortA I/O setzen&lt;br /&gt;
	banksel	ADCON1			; Zur Bank von ADCON1 umschalten&lt;br /&gt;
	movlw	B'10010100'		; Alle Analog VDD=VREF, Right jutyfy, fosc/8, AN0,1,3=AN, AN2,4-7=Dig.&lt;br /&gt;
	movwf	ADCON1			; Move w to ADCON1&lt;br /&gt;
	banksel	ADCON0			; zu Bank von TRISA umschalten&lt;br /&gt;
	movlw	B'01000001'		; Enable ADC&lt;br /&gt;
	movwf	ADCON0			; Move w to ADCON0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch_read&lt;br /&gt;
	; Y&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bsf	XP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bcf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD1 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	ylow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	yhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	; X&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	bsf	YP&lt;br /&gt;
	bcf	ADCON0,5			; ADC Auswehlen&lt;br /&gt;
	bsf	ADCON0,4&lt;br /&gt;
	bsf	ADCON0,3&lt;br /&gt;
	call	adc_read			; Read ADC AD3 Daten&lt;br /&gt;
	banksel	ADRESL&lt;br /&gt;
	movf	ADRESL,w&lt;br /&gt;
	movwf	xlow&lt;br /&gt;
	banksel	ADRESH&lt;br /&gt;
	movf	ADRESH,w&lt;br /&gt;
	movwf	xhigh&lt;br /&gt;
	bcf	YP&lt;br /&gt;
	bcf	XP&lt;br /&gt;
	return&lt;br /&gt;
adc_read&lt;br /&gt;
	movlw	D'30'			; Wait Acquisition Time 20MHz&lt;br /&gt;
	movwf	count&lt;br /&gt;
adc_read_loop&lt;br /&gt;
	decfsz	count,F&lt;br /&gt;
	goto	adc_read_loop&lt;br /&gt;
	bsf	ADCON0,GO		; Setze ADCON0,GO, Int A/D Conversation&lt;br /&gt;
adc_read_loop_1				; Wen ADC bereit &lt;br /&gt;
	btfsc	ADCON0,GO		; Ist ADCON0,GO = 0 dann ubergehe den nesten Befehl&lt;br /&gt;
	goto	adc_read_loop_1		; Warte bis ADC fertig&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 12:00, 23. Jan 2010 (CET)&lt;br /&gt;
&lt;br /&gt;
== Schieberegister (z.b. CD4094) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; Datenleitungen Schiberegister alles Ausgänge&lt;br /&gt;
	#define		CLK		PORTB, 0&lt;br /&gt;
	#define		D	 	PORTB, 1&lt;br /&gt;
	#define		STR		PORTB, 2&lt;br /&gt;
	#define		OE		PORTB, 3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 cd4094_send&lt;br /&gt;
	banksel	PORTB&lt;br /&gt;
        bcf             OE&lt;br /&gt;
	bcf		STR&lt;br /&gt;
	btfsc	cdsend, 0&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 0&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 1&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 1&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 2&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 2&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 3&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 3&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 4&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 4&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 5&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 5&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 6&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 6&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	btfsc	cdsend, 7&lt;br /&gt;
	bsf		D&lt;br /&gt;
	btfss		cdsend, 7&lt;br /&gt;
	bcf		D&lt;br /&gt;
	bsf		CLK&lt;br /&gt;
	bcf		CLK&lt;br /&gt;
	bsf		STR&lt;br /&gt;
        bsf             OE&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
== MAX7456 (S/W OSD) ==&lt;br /&gt;
&lt;br /&gt;
Variabeln und I/0:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	cblock	0x70		; Variabeln ab 0x70 setzen alle Register max 16stk.&lt;br /&gt;
	SPI_DATA_WRITE		; Zu Sendene SPI Daten&lt;br /&gt;
	SPI_DATA_READ		; Gelesend SPI Daten&lt;br /&gt;
	m_char			; Maxim7456 und sda5708 Zeichen&lt;br /&gt;
	m_pos			; Maxim7456 Position&lt;br /&gt;
	endc 			; Variabeln setzen beenden&lt;br /&gt;
&lt;br /&gt;
	#define	SPI_CS	PORTC, 7; SPI Slave Select max7456&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Config:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	; PORTC&lt;br /&gt;
	banksel	TRISC			; auf Bank 1 umschalten&lt;br /&gt;
	movlw	B'10010000'		; PortC I/O setzen (1=In, 0=Out) (Reinfolge RC7,RC6...)&lt;br /&gt;
	movwf	TRISC			; PortC I/O setzen&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	clrf	PORTC			; PortC auf 0 setzen&lt;br /&gt;
	; SPI&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
	movlw	B'11000000'		; Mitlere Geschwindigkeit Output Time &lt;br /&gt;
	movwf	SSPSTAT&lt;br /&gt;
	banksel	SSPCON&lt;br /&gt;
	movlw	B'00100001'		; MODE 1,1, SPI MASTER, 1/16 Tosc SSP ON&lt;br /&gt;
	movwf	SSPCON&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf	SPI_CS			; SPI Slave Select aus (high)&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
SPI  Sende/Enfangs Rotinen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SPI_Send&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS			; Chip Select an (Low)&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SPI_DATA_WRITE, W&lt;br /&gt;
	movwf	SSPBUF&lt;br /&gt;
	banksel	SSPSTAT&lt;br /&gt;
SPI_Wait&lt;br /&gt;
	btfss	SSPSTAT, BF		; Ist das Senden Komplet ?&lt;br /&gt;
	goto	SPI_Wait			; Wen nicht gehe zu SPIWait&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf 		SPI_CS			; Chip Select aus (High)&lt;br /&gt;
	return &lt;br /&gt;
SPI_Read&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bcf		SPI_CS&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	SSPBUF&lt;br /&gt;
	movf	SSPBUF, W&lt;br /&gt;
	movwf	SPI_DATA_READ&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	nop&lt;br /&gt;
	banksel	PORTC&lt;br /&gt;
	bsf		SPI_CS&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Defines ASCII to MAX7456 Charset und Config und Schreibrotienen (Achtung es kann sein das die #define nicht mit mpasm Funktioniert mit gpasm wird groß und kleinschreibung unterschiden):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
max7456_define				; Defines für den max7456 Zeichensatz&lt;br /&gt;
	#define	m_sp	0x00		; Space&lt;br /&gt;
	#define	m_1		0x01&lt;br /&gt;
	#define	m_2		0x02&lt;br /&gt;
	#define	m_3		0x03&lt;br /&gt;
	#define	m_4		0x04&lt;br /&gt;
	#define	m_5		0x05&lt;br /&gt;
	#define	m_6		0x06&lt;br /&gt;
	#define	m_7		0x07&lt;br /&gt;
	#define	m_8		0x08&lt;br /&gt;
	#define	m_9		0x09&lt;br /&gt;
	#define	m_0		0x0A&lt;br /&gt;
	#define	m_A		0x0B&lt;br /&gt;
	#define	m_B		0x0C&lt;br /&gt;
	#define	m_C		0x0D&lt;br /&gt;
	#define	m_D		0x0E&lt;br /&gt;
	#define	m_E		0x0F&lt;br /&gt;
	#define	m_F		0x10&lt;br /&gt;
	#define	m_G		0x11&lt;br /&gt;
	#define	m_H		0x12&lt;br /&gt;
	#define	m_I		0x13&lt;br /&gt;
	#define	m_J		0x14&lt;br /&gt;
	#define	m_K		0x15&lt;br /&gt;
	#define	m_L		0x16&lt;br /&gt;
	#define	m_M	0x17&lt;br /&gt;
	#define	m_N		0x18&lt;br /&gt;
	#define	m_O		0x19&lt;br /&gt;
	#define	m_P		0x1A&lt;br /&gt;
	#define	m_Q		0x1B&lt;br /&gt;
	#define	m_R		0x1C&lt;br /&gt;
	#define	m_S		0x1D&lt;br /&gt;
	#define	m_T		0x1E&lt;br /&gt;
	#define	m_U		0x1F&lt;br /&gt;
	#define	m_V		0x20&lt;br /&gt;
	#define	m_W	0x21&lt;br /&gt;
	#define	m_X		0x22&lt;br /&gt;
	#define	m_Y		0x23&lt;br /&gt;
	#define	m_Z		0x24&lt;br /&gt;
	#define	m_a		0x25&lt;br /&gt;
	#define	m_b		0x26&lt;br /&gt;
	#define	m_c		0x27&lt;br /&gt;
	#define	m_d		0x28&lt;br /&gt;
	#define	m_e		0x29&lt;br /&gt;
	#define	m_f		0x2A&lt;br /&gt;
	#define	m_g		0x2B&lt;br /&gt;
	#define	m_h		0x2C&lt;br /&gt;
	#define	m_i		0x2D&lt;br /&gt;
	#define	m_j		0x2E&lt;br /&gt;
	#define	m_k		0x2F&lt;br /&gt;
	#define	m_l		0x30&lt;br /&gt;
	#define	m_m		0x31&lt;br /&gt;
	#define	m_n		0x32&lt;br /&gt;
	#define	m_o		0x33&lt;br /&gt;
	#define	m_p		0x34&lt;br /&gt;
	#define	m_q		0x35&lt;br /&gt;
	#define	m_r		0x36&lt;br /&gt;
	#define	m_s		0x37&lt;br /&gt;
	#define	m_t		0x38&lt;br /&gt;
	#define	m_u		0x39&lt;br /&gt;
	#define	m_v		0x3A&lt;br /&gt;
	#define	m_w		0x3B&lt;br /&gt;
	#define	m_x		0x3C&lt;br /&gt;
	#define	m_y		0x3D&lt;br /&gt;
	#define	m_z		0x3E&lt;br /&gt;
	#define	m_KLa	0x3F	; (&lt;br /&gt;
	#define	m_KLz	0x40		; )&lt;br /&gt;
	#define	m_.		0x41&lt;br /&gt;
	#define	m_?		0x42&lt;br /&gt;
	#define	m_sem	0x43		; ;&lt;br /&gt;
	#define	m_:		0x44&lt;br /&gt;
	#define	m_ko	0x45		; ,&lt;br /&gt;
	#define	m_ag	0x46		; Agostroff&lt;br /&gt;
	#define	m_bs	0x47		; Backslasch&lt;br /&gt;
	#define	m_as	0x48		; Anfürungsstriche&lt;br /&gt;
	#define	m_minus  0x49		; Minus&lt;br /&gt;
	#define	m_ka	0x4A		; &amp;lt;&lt;br /&gt;
	#define	m_ga	0x4B	; &amp;gt;&lt;br /&gt;
	#define	m_at	0x4C	; @ oder at&lt;br /&gt;
	#define	m_wait	0xfb		; Wartezeichen&lt;br /&gt;
	#define	m_ls		0xf9		; Lautsprecher&lt;br /&gt;
	#define	m_lso	0xfa		; Tonsignal&lt;br /&gt;
	#define	m_ff		0xff		; Ausgefültes feld&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_conf					; Max7456 Config&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001000'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 0=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x01				; VM1 Video Mode Register 1&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00000100'		; 0 = NA, 000=Background MODE Brightness 100%, 11=Blinking Time 160ms, 00=Blinking Duty Cycle BT:BT&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x02				; HOS Horizontal Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00101111'		; 00 = NA, 100000 = Horitzontal Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x03				; VOS Vertical Offset Register&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'00010111'		; 000 = NA, 10000 = Vertical Offset&lt;br /&gt;
	movwf	SPI_DATA_WRITE&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_cls					; max7456 ausgabe Löschen&lt;br /&gt;
	movlw	0x00				; VM0 Video Mode Register 0 (Write)&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	B'01001010'		; 0 , 1=PAL, 00=Auto Sync, 1=Enable OSD, 0=Enable OSD immer, 1=SW RST, 0=Enable Video Buffer&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	call		max7456_conf&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_high				; High adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 0x00, Letzten 256 Zeichen High=0xff &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0xFF&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_add_low				; Low Adressbereich&lt;br /&gt;
	movlw	0x05				; Ersten 256 zeichen Low = 000, Letzten 256 Zeichen High=225 &lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movlw	0x00&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&lt;br /&gt;
max7456_send_char&lt;br /&gt;
	movlw	0x06				; Zeichen Position links nach rechts erste reihe 0-29, 30-......&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_pos, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	movlw	0x07				; Zeichen Sonderzeichen sihe Define in max7456.inc&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send&lt;br /&gt;
	movf	m_char, W&lt;br /&gt;
	movwf	SPI_DATA_WRITE	&lt;br /&gt;
	call		SPI_Send	&lt;br /&gt;
	return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zeichen Senden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	movlw	D'12'			; Position&lt;br /&gt;
	movwf	m_pos&lt;br /&gt;
	movlw	m_e			; Zeichen (hier das kleine e) oder direkt den wert des Zeichens im MAX7456 REG.&lt;br /&gt;
	movwf	m_char&lt;br /&gt;
	call	max7456_send_char; Schreiben&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
High/low Adressbereich (low = ersten 256 Zeichen, High die letzten 128 Zeichen);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	call		max7456_add_low	; Low Adressbereich&lt;br /&gt;
	;call		max7456_add_high; Low Adressbereich&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Theborg|Theborg]] 23:13, 15. Sep 2009 (CEST)&lt;br /&gt;
&lt;br /&gt;
= PIC18(F/LF)xxxx =&lt;br /&gt;
&lt;br /&gt;
== Programmspeicher (Flash) beschreiben und lesen ==&lt;br /&gt;
&lt;br /&gt;
Weil das Programteil mit PAD erstellt wurde, ist fast nicht kommentiert. Zuerst wird der benötigte Flash-Bereich gelöscht und danach werden dort Daten aus RAM kopiert (gespeichert). Dazu wurden zwei Register &amp;quot;Tmp&amp;quot; und &amp;quot;Tmp1&amp;quot; benutzt, die im Program definiert werden müssen.&lt;br /&gt;
&lt;br /&gt;
 Store		movff	F2,FS2&lt;br /&gt;
 		movff	F1,FS1&lt;br /&gt;
 		movff	F0,FS0&lt;br /&gt;
 		clrf	TBLPTRU			; erase flash memory (7BC0-7FFF)&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		movlw	0x11&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 FlashEraseL	bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bsf	EECON1,FREE&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		bra	$-2&lt;br /&gt;
 		movlw	0x40&lt;br /&gt;
 		addwf	TBLPTRL&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		incf	TBLPTRH,1&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	FlashEraseL&lt;br /&gt;
 		lfsr	FSR0,0x0020		; write parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	4&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgPL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFPL	movff	POSTINC0,TABLAT&lt;br /&gt;
 		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFPL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgPL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 WriteSMP	lfsr	FSR0,0x100		; write samples 1024 bytes (7C00-7FFF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		tblrd*-&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		movwf	Tmp1&lt;br /&gt;
 FlashProgL	movlw	8&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 WriteFL		movff	POSTINC0,TABLAT&lt;br /&gt;
  		tblwt+*&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		bra	WriteFL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		bcf	INTCON,GIE&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	PIR2,EEIF&lt;br /&gt;
 		bsf	INTCON,GIE&lt;br /&gt;
 		decfsz	Tmp1,1&lt;br /&gt;
 		bra	FlashProgL&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Um die Daten aus Flash zurück auf ursprüngliche Adressen im RAM zu übertragen, wurde folgendes Programmfragment verwendet in dem Register &amp;quot;STmp&amp;quot; benutzt wurde, der auch im Programm definiert werden muss.&lt;br /&gt;
&lt;br /&gt;
 Restore		lfsr	FSR0,0x0020		; restore parameter 32 bytes (7BC0-7BDF)&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7B&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		movlw	0xC0&lt;br /&gt;
 		movwf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 FlashRAMP	movlw	0x20&lt;br /&gt;
 		movwf	STmp&lt;br /&gt;
 FlashRAMPL	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAMPL&lt;br /&gt;
 		lfsr	FSR0,0x100		; restore samples 1024 bytes (7C00-7FFF)	&lt;br /&gt;
 		clrf	TBLPTRU&lt;br /&gt;
 		movlw	0x7C&lt;br /&gt;
 		movwf	TBLPTRH&lt;br /&gt;
 		clrf	TBLPTRL&lt;br /&gt;
 		bsf	EECON1,EEPGD&lt;br /&gt;
 		bcf	EECON1,CFGS&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 		call	FlashRAM&lt;br /&gt;
 FlashRAM	clrf	STmp&lt;br /&gt;
 FlashRAML	tblrd*+&lt;br /&gt;
 		movff	TABLAT,POSTINC0&lt;br /&gt;
 		decfsz	STmp,1&lt;br /&gt;
 		bra	FlashRAML&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
== Hex Dec Wandlung ==&lt;br /&gt;
&lt;br /&gt;
Weil das UP mit PAD erstellt wurde, ist es fast nicht kommentiert. Genaue Funktionsweise und Definitionen der Register sind im http://www.rn-wissen.de/index.php/PIC_Assembler#Hex_Dec_Wandlung beschrieben.&lt;br /&gt;
&lt;br /&gt;
Übrigens, das UP wurde ursprünglich für PIC18... erstellt und danach auf PIC12.. und PIC16... umgeschrieben. Durchs Vergleichen sieht man den Unterschied zwischen den PIC Familien.&lt;br /&gt;
&lt;br /&gt;
 Hex_Dec		call	CClr			; Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		call	DClr&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x18			; 24 bit Hex (6 Ziffer) &amp;gt; 32 bit Dec (8 Ziffer)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 Hex_DecL	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		bra	Hex_DecL&lt;br /&gt;
 		return&lt;br /&gt;
 CClr		lfsr	FSR0,C4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		bra	RegClr&lt;br /&gt;
 DClr		lfsr	FSR0,D4&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 RegClr		movwf	ATmp&lt;br /&gt;
 RegClrL		clrf	POSTINC0&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	RegClrL&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		lfsr	FSR0,C0&lt;br /&gt;
 		lfsr	FSR1,B0&lt;br /&gt;
 CopyReg		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 CopyRegL	movff	POSTDEC0,POSTDEC1       ; INDF0 in INDF1 kopieren und Zeiger dekrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	CopyRegL		&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		lfsr	FSR0,B0			; C+B&amp;gt;C&lt;br /&gt;
 		lfsr	FSR1,C0&lt;br /&gt;
 		bra	AddReg&lt;br /&gt;
 AddDC		lfsr	FSR0,C0			; D+C&amp;gt;D&lt;br /&gt;
 		lfsr	FSR1,D0&lt;br /&gt;
 AddReg		bcf	_Ferr&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	5&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRegL		bcf	_Fcra&lt;br /&gt;
 		movf	INDF0,0&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		bra	AddRegN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF1,0&lt;br /&gt;
 		daw&lt;br /&gt;
 		movwf	INDF1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddRegN		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTDEC0,1              ; Zeiger für INDF0 um 1 dekrementieren&lt;br /&gt;
 		movf	POSTDEC1,1              ; Zeiger für INDF1 um 1 decrementieren&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		bra	AddRegL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		lfsr	FSR0,A2	&lt;br /&gt;
 RRotRb		movlw	3			; A Rregister um 1 bit nach rechts rotieren&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL		bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF0,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrcf	INDF0,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movf	POSTINC0,1              ; Zeiger für INDF0 um 1 inkrementieren             &lt;br /&gt;
 		decfsz	RTmp,1&lt;br /&gt;
 		bra	RRotRbL&lt;br /&gt;
 		return &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16873</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16873"/>
				<updated>2010-08-07T21:51:02Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* PIC Profiler */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).&lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16872</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16872"/>
				<updated>2010-08-07T21:47:31Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* PIC Trainer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @SWR equ 0x7F anstatt 0x4F).Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16871</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16871"/>
				<updated>2010-08-07T21:44:54Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* PIC RAM Monitor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Entsprechend können auch alle im Programm benutzte Register höchstmögliche Adressen im RAM haben (z.B. @Tmp equ 0x7F anstatt 0x4F). &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16868</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16868"/>
				<updated>2010-08-05T13:37:07Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Software */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben. Siehe dazu: http://ww1.microchip.com/downloads/en/AppNotes/00818a.pdf&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16867</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16867"/>
				<updated>2010-08-05T13:19:12Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben.&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PIC18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16866</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16866"/>
				<updated>2010-08-04T18:34:16Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Ausführliche Beschreibung zu den Befehlen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben.&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen. Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18F... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PICF18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16864</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16864"/>
				<updated>2010-08-01T09:19:41Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben.&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18F... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PICF18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16863</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16863"/>
				<updated>2010-08-01T09:13:22Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* PIC Profiler */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben.&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18F... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PICF18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		swapf	@SSR,0 		; STATUS Register&lt;br /&gt;
 		movwf	STATUS 		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16862</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16862"/>
				<updated>2010-08-01T03:47:43Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Ausführliche Beschreibung zu den Befehlen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben.&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Lese Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Lese Labelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Lese Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Lese Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Schreibe Tabelle ohne Änderung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Schreibe Tabelle mit Nacherhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Schreibe Tabelle mit Nacherniedrigung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Schreibe Tabelle mit Vorerhöhung des Zeigers &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18F... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PICF18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		movf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		movf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		movf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		movf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16861</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=16861"/>
				<updated>2010-08-01T03:18:21Z</updated>
		
		<summary type="html">&lt;p&gt;PICture: /* Ausführliche Beschreibung zu den Befehlen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einführung =&lt;br /&gt;
&lt;br /&gt;
== Bit, Byte, Nibble, Bin und Hex ==&lt;br /&gt;
&lt;br /&gt;
Ein Mikrocontroller (kurz: µC) kann eigentlich nur durch ein Portpin eine Spannung einlesen bzw. ausgeben. Er kann aber nur erkennen, ob eine Spannung vorhanden ist oder nicht. Wenn fast keine Spannung vorhanden ist erkennt er das als 0 und wenn eine Spannung fast so gross, wie seine Versorgungsspannung anliegt, als 1.&lt;br /&gt;
&lt;br /&gt;
Genauso bei der Ausgabe, wenn er 0 ausgibt ist auf dem Portpin fast keine Spannung, wenn 1, eine Spannung fast gleich gross seiner Versorgungsspannung. Und das ist ein Bit, die kleinste Menge einer Information. Das Bit ist binär, d.h. es kann nur zwei unterschiedliche Werte haben: 0 oder 1.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (parallel) 8 Bits haben, dann ist es ein Byte, das 256 Bitkombinationen von 00000000b bis 11111111b enthält, weil ein Bit (X) auf jeder Stelle 0 bzw. 1 sein kann.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#007fff&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;b&amp;quot; bedeutet, dass es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jedes Bit eine Stelle benötigt.&lt;br /&gt;
&lt;br /&gt;
Um die Schreibweise zu verkürzen, wurden hexadezimale (kurz: hex) Zahlen eingeführt. Zuerst wurde ein Byte auf zwei 4-Bit Halbbytes (Nibbles) verteilt und danach ein Nibble als Ziffer genommen. Weil 4 Bits 16 Kombinationen ergeben, haben die Ziffer 0 bis 9 aus dem Dezimalsystem (d) nicht ausgereicht und wurden um Buchstaben A bis F erweitert. Die hexadezimalen Zahlen haben ein &amp;quot;h&amp;quot; Zeichen am Ende. Für die Zahlen 0 bis 9 sind die (h) und&lt;br /&gt;
(d) Zeichen nicht nötig, da sie beide gleich den entsprechenden bin Zahlen sind.&lt;br /&gt;
&lt;br /&gt;
Die Umwandlung zwischen bin, hex und dec Zahlen für ein Nibble zeigt folgende Tabelle:&lt;br /&gt;
&lt;br /&gt;
             0b = 0h = 0d      100b = 4h = 4d     1000b = 8h = 8d     1100b = Ch = 12d&lt;br /&gt;
             1b = 1h = 1d      101b = 5h = 5d     1001b = 9h = 9d     1101b = Dh = 13d&lt;br /&gt;
            10b = 2h = 2d      110b = 6h = 6d     1010b = Ah = 10d    1110b = Eh = 14d&lt;br /&gt;
            11b = 3h = 3d      111b = 7h = 7d     1011b = Bh = 11d    1111b = Fh = 15d&lt;br /&gt;
&lt;br /&gt;
Damit kann ein Byte mit zwei hex Ziffern definiert werden z.B. 1100 0011b = C3h. Für zwei Bytes braucht man 4 hex Ziffern z.B.&lt;br /&gt;
&lt;br /&gt;
101 0111 1010 1001b = 57A9h, usw. Für MPASM wird sehr oft die Schreibweise für hex Zahlen 0x57A9 oder 0xC3 benutzt.&lt;br /&gt;
&lt;br /&gt;
So wie im Dezimalsystem werden führende Nullen nicht geschrieben. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führender Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man das Teil der Hardware, in das eine Information geschrieben, gespeichert und von dort wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speichern: flüchtige und nichtflüchtige. Die Information die sich im flüchtigen Speicher befindet, geht verloren, wenn die Versorgungsspannung des Speichers unterbrochen oder abgeschaltet wird. Bei PICs ist es Datenspeicher (RAM).&lt;br /&gt;
&lt;br /&gt;
Wenn die Versorgungsspannung vom nichtflüchtigen Speicher abgeschaltet wird, ist die gespeicherte Information zwar momentan nicht lesbar, bleibt aber erhalten und sobald der Speicher wieder mit Spannung versorgt wird, kann sie ausgelesen werden. Ein PIC hat zwei solche Speicher: Programmspeicher (Flash) und EEPROM.&lt;br /&gt;
&lt;br /&gt;
Der wichtigste Unterschied zwischen den Speicherarten ist, dass die flüchtigen direkt (sehr schnell) beschreibbar sind, dagegen das Beschreiben des nichtflüchtigen Speichers spezielle Algorithmen benötigt, die im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Speicher besitzen eine bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat eine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
PIC Prozessoren haben drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8 Bit Breite und Programmspeicher (Flasch) bei Basic-Line hat 12-bittige, Mid-Range 14-bittige und High-End 8-bittige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bittige Speicherstelle im RAM wird bei PICs Register genannt und kann so skizziert werden:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;table border=0 cellpadding=3 cellspacing=2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td align=middle bgcolor=&amp;quot;#CCCCCC&amp;quot; style=&amp;quot;border:1px solid #333333&amp;quot;&amp;gt;X&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; MSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=6&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt; LSB &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 6&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 5&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 4&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 3&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 2&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td bgcolor=&amp;quot;#007fff&amp;quot;&amp;gt;bit 0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;High Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=4 align=middle bgcolor=#ff8305&amp;gt;Low Nibble &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=8 align=middle bgcolor=#810f40&amp;gt; &amp;lt;font color=#ffffff&amp;gt;Byte&amp;lt;/font&amp;gt; &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bit 7 wird als hochwertigstes (MSB = Most Significant Bit) und bit 0 als niederwertigstes (LSB = Least Significant Bit) bezeichnet. Jedes Bit im Register (X) kann gleich 0 bzw. 1 sein. In einem Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Datenbyte in ein Register zu schreiben oder aus einem Register zu lesen, muss zuerst das Register durch seine Adresse gewählt werden. Dafür gibt es beim PIC folgende Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per absolute Adresse:   movwf   0x20&lt;br /&gt;
&lt;br /&gt;
Direkte Adressierung per vorher definiertem Namen des Registers (z.B. Temp  equ  0x20):   movwf   Temp&lt;br /&gt;
&lt;br /&gt;
Indirekte Adressierung durch &amp;quot;FSR&amp;quot; Register, in das die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird. Durch Zugriff mittels &amp;quot;INDF&amp;quot; Register wird auf die Speicherstelle zugegriffen, die durch das Register &amp;quot;FSR&amp;quot; adressiert wird. (&amp;quot;INDF&amp;quot; ist dabei kein real in Hardware implementiertes Register). Wie vorher wurde &amp;quot;Temp  equ  0x20&amp;quot; definiert und weiter:&lt;br /&gt;
&lt;br /&gt;
       movlw   Temp      ;ins W-Register wird die absolute Adresse des Registers &amp;quot;Temp&amp;quot; geladen&lt;br /&gt;
       movwf   FSR       ;diese Adresse wird ins &amp;quot;FSR&amp;quot; Register kopiert&lt;br /&gt;
       movf    INDF,0    ;der Wert aus dem indirekt adressierten Register &amp;quot;Temp&amp;quot;&lt;br /&gt;
                         ;wird aus dem &amp;quot;INDF&amp;quot; Register ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 12 bzw. 14-bittigem Befehl, der mit Datenspeicher verbunden ist, für die Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zur Adresse 7Fh (128d) Register direkt ansprechen können, ist bei Basic-Line und Mid-Range PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Auswahl einer Bank sind zwei Bits &amp;quot;RP0&amp;quot; und &amp;quot;RP1&amp;quot; im &amp;quot;STATUS&amp;quot; Register zuständig. Die Anzahl der Bänke und ihre Verwendung ist von der gesamten Größe des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden.&lt;br /&gt;
&lt;br /&gt;
Die Beschreibung allen SFRs (Special Funktion Register), in den sämtliche Funktionen des PICs festgelegt werden, befinden sich im Datenblatt unter &amp;quot;Memory Organisation&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 bzw. 75 Befehle zu erlernen, was seine Programmierung im Vergleich zu anderen  µCs deutlich vereinfacht. Jeder Befehl benötigt im Programmspeicher nur eine Speicherstelle und im Quellcode nur eine Zeile. Die Ausführung des Befehls dauert, abhängig vom Befehl, 1 bis 2 Prozessortakte.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der PIC's von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU (Central Processing Unit) besitzen. Der Vorteil zur &amp;quot;von Neumann&amp;quot;-Architektur ist, dass sich die Busgrößen damit unterscheiden können. Das ermöglicht eine größere Bandbreite.&lt;br /&gt;
&lt;br /&gt;
Der Befehl kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in 4 verschiedene Vorgänge. Wärend der neue Befehl eingelesen (&amp;quot;fetch&amp;quot;) wird, wird der vorige gerade gelesen (&amp;quot;read&amp;quot;) und der vorvorige verarbeitet (&amp;quot;execute&amp;quot;) und der vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heißt, 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen entspricht die Taktfrequenz der CPU der durch 4 geteilten Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fetch)        &amp;lt;-------   Flash       |&lt;br /&gt;
                 2.Daten lesen (read)          &amp;lt;-------   RAM         | 1 Prozessortakt =&lt;br /&gt;
                 3.Daten verarbeiten (execute)                        | 4 Oszillatortakte&lt;br /&gt;
                 4.Daten schreiben (write)     -------&amp;gt;   RAM         |  &lt;br /&gt;
                                                                     -&lt;br /&gt;
&lt;br /&gt;
Nur o.g. CPU Vorgänge sind direkt möglich. Es können deswegen keine Befehle aus dem RAM oder EEPROM ausgeführt werden. Um ein Databyte aus einem RAM Register in ein anderes zu kopieren, muss er zuerst aus dem ersten RAM Register in das W-Register (eigenen s.g. Arbeitsregister des CPU) und erst davon in das zweite RAM Register kopiert werden.&lt;br /&gt;
&lt;br /&gt;
Der Prozessor hat einen kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (program counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die Adresse des momentan ausführbaren Befehls. Nach der Ausführung jedes Befehls wird der PC um 1 erhöht und &amp;quot;zeigt&amp;quot; somit auf den nächsten Befehl im Programmspeicher, der zum Ausführen wäre. Wenn der nächste Befehl aber z.B. ein Sprung (&amp;quot;call&amp;quot;) ist, wird die Adresse aus dem Befehl genommen. Nach dem Sprung wird das Programm bis zum Befehl &amp;quot;return&amp;quot; ausgeführt und danach muss der Prozessor zurückspringen, und zwar, genau zur nächsten Adresse im Programmspeicher nach dem &amp;quot;call&amp;quot; Befehl.&lt;br /&gt;
&lt;br /&gt;
Um dies zu ermöglichen, wird vor dem Sprung die Adresse aus dem PC &amp;quot;auf dem Stapel gelegt&amp;quot; (gespeichert). Für den Rücksprung wird die abgelegte Adresse &amp;quot;aus dem Stapel genommen&amp;quot; (vom Stapel in den PC geladen). Beim Auftreten eines Interrupts wird auf dem Stapel die Adresse, der zuletzt ausgeführten Zeile abgelegt, damit der Prozessor, wenn er nach der Ausführung der &amp;quot;Interruppt Service Routine&amp;quot; (ISR) an &amp;quot;retfie&amp;quot; kommt, das unterbrochene Programm an der richtigen Stelle wieder startet. &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 bzw. 31 Adressen speichern, deswegen darf nur entsprechende Anzahl von nacheinander folgenden &amp;quot;call&amp;quot; Befehlen benutzt werden. Wenn ein Interrupt benutzt wird, reduziert sich es um 1, da eine Speicherstelle immer für die Adresse, an der das Programm unterbrochen wurde, reserviert werden muss. Sonst findet der Prozessor nicht mehr zurück und springt in die &amp;quot;Nirvana&amp;quot; , was einen Absturz des Programms bedeutet. Bei dem &amp;quot;goto&amp;quot; Befehl wird die nächste Adresse nicht gespeichert, da der Prozessor nicht zurückkehren braucht.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen PICs möglich. Der Lese und Schreibzugriff auf den Programmspeicher ist aber nur bei wenigen PIC-Typen (z.B. PIC16F87X) möglich. Dies ermöglicht ein &amp;quot;sich selbst Programmieren&amp;quot;, was bei Bootloadern genutzt wird.&lt;br /&gt;
&lt;br /&gt;
== Assembler ==&lt;br /&gt;
&lt;br /&gt;
Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur eine bestimmte CPU versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hex Zahlen besteht.&lt;br /&gt;
&lt;br /&gt;
Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für einen CPU hat somit ein &amp;quot;Namen&amp;quot;, der aus der englischen Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 2 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie, wegen des grossen Aufwands bei der Erstellung von umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eingebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder die nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich sehr gut für kleine Anwendungen (meistens Steuerungen) mit µC, weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem Bit im Programm und einer Spannung am I/O Pin besteht. Aus dem Grund sind Hardware-Kenntnisse sehr vorteilhaft. Man kann sagen, dass je mehr externer Hardware, um so weniger Software, und umgekehrt. In der Praxis wird immer ein Kompromiss gesucht.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlossenen Hardware und dem entsprechenden Programm kann ein µC umfangreiche Aufgaben realisieren, die fast unbegrenzt und schwer vorstellbar sind.&lt;br /&gt;
&lt;br /&gt;
Die Aufgabe eines ASM-Programmierers ist,  ein Programm zu schreiben, das das Assemblerprogramm (z.B. MPASM) fehlerfrei in die Machinensprache assembliert (&amp;quot;übersetzt&amp;quot;), die dann eine bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplant funktioniert. &lt;br /&gt;
&lt;br /&gt;
Die beste Methode um ASM Programmierung zu lernen ist einfach mit den Befehlen, wie mit &amp;quot;LEGO&amp;quot; Bausteinen, zu spielen. Dafür wurde ein Programm &amp;quot;PIC Trainer&amp;quot; entwickelt. Der PIC kann durch ein Programmfehler nicht kaputtgehen. Vorsicht ist nur bei der angeschlossener Hardware nötig, da ein Fehler den PIC oder die Hardware sogar &amp;quot;töten&amp;quot; kann. &lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Bei der Programmerstellung fängt man damit an, ein PAD zu erstellen, das alle Programmschritte enthält.&lt;br /&gt;
&lt;br /&gt;
Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung &amp;quot;.asm&amp;quot; (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder [http://gputils.sourceforge.net/ GPASM]) von dem für Menschen noch verständlichen Code in die Maschinensprache assembliert und als Textdatei mit Erweiterung &amp;quot;.hex&amp;quot; gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen (&amp;quot;gebrannt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm MPASM kann kostenlos von der Homepage des Herstellers von PICs [http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&amp;amp;nodeId=1406&amp;amp;dDocName=en019469&amp;amp;part=SW007002] runtergeladen werden. Es muss zuerst vom Downloads die &amp;quot;MPLAB IDE v7.50 Full Zipped Installation&amp;quot; runtergeladen und erst danach können gewählte Programme (z.B. nur MPASM) installiert werden. Für MPASM Benutzer werden auch folgende &amp;quot;.pdf&amp;quot; Dateien empfohlen:&lt;br /&gt;
&lt;br /&gt;
MPASM/MPLINK User's Guide (2628 KB) [Benutzerhandbuch]    &lt;br /&gt;
&lt;br /&gt;
MPASM™/MPLINK™ PICmicro® Quick Chart (81 KB) [Kurzübersicht]    &lt;br /&gt;
   &lt;br /&gt;
Nach dem Einschalten der Betriebsspannung des µC, fängt der CPU an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.&lt;br /&gt;
&lt;br /&gt;
Aber wann das Programm endet? Natürlich wenn die Versorgungsspannung abgeschaltet wird. Nein! Das ist die einfachste Lösung um ein laufendes Programm an zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine, um es an einer definierten Stelle zu beenden.&lt;br /&gt;
&lt;br /&gt;
Wenn an den µC angeschlossene externe Hardware (z.B. Grafikdisplay), eine bestimmte Befehlsfolge vor dem Abschalten benötigt oder wichtige Daten (in EEPROM oder Flash) abgespeichert werden sollen, darf die Spannung erst dann abgeschaltet werden, wenn die CPU eine Meldung ausgibt, dass sie sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befindet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann die CPU zum letzten Fragment des ASM Programms vor dem &amp;quot;STOP&amp;quot; gehen soll.&lt;br /&gt;
&lt;br /&gt;
== Grundbeschaltung ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von einem PIC kann sofort nach dem Einschalten der Versorgungsspannung (z.B. + 5V DC) arbeiten. Allerdings nur, wenn er den Takt, in dem er die Befehle ausführen soll, vorgegeben hat. Manche PICs besitzen einen internen RC-Oszillator, (z.B. PIC12F629, PIC16F630, PIC16F628, usw.). Bei diesen reicht es die Versorgungsspannung anzulegen und sie laufen bereits.&lt;br /&gt;
&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, usw.) und brauchen fürs Funktionieren zusätzliche Bauteile. Grundsätzlich gibt es mehrere Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
* Quarz oder Keramik-Resonator + 2 Kondensatoren (LP,HS oder XT) &lt;br /&gt;
* Keramik-Resonator mit integrierten Kondensatoren (HS oder XT)&lt;br /&gt;
* Quarzoszillator (EC); genau und stabil&lt;br /&gt;
* Widerstand + Kondensator (RC); keine hohe Frequenzstabilität&lt;br /&gt;
&lt;br /&gt;
Die entsprechenden Bauteile werden an die Pins OSC1/OSC2 angeschlossen, um den notwendigen Prozessortakt zu erzeugen. Im Konfiguration-Word &amp;quot;__config&amp;quot; muss noch angegeben werden, welcher Oszillator (LP, HS, XT bzw. RC) verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Desweiteren existiert ein MCLR-Pin, der beim PIC einen Neustart (=Reset) auslösen kann (Low-Pegel). Diesen Pin sollte man, wenn er in &amp;quot;__config&amp;quot; aktiviert ist, über einen Widerstand (pull-up) an Versorgungsspannung legen, damit der PIC anfängt, sein Programm abzuarbeiten. Der Anschluss wird auch für die Programmierung benötigt. Beim sog. High-Voltage-Programming wird MCLR auf ca. 12-14 Volt gelegt, um den PIC in den Programmiermodus zu schalten. Bei manchen PICs kann dieser Anschluss auch als normalen I/O Pin eingestellt werden. In dem Fall, bei ICSP Benutzung, soll noch eine Diode zwischen den pull-up und Versorgungsspannung  angeschlossen werden, um die an PIC angeschlossene Hardware während der Programmierung vom Auftreten der Vpp an Vcc zu schützen und die Vpp nicht zu belasten.&lt;br /&gt;
&lt;br /&gt;
                                      VCC&lt;br /&gt;
                                       +&lt;br /&gt;
                                       |&lt;br /&gt;
                                       V Diode&lt;br /&gt;
                                       -&lt;br /&gt;
                                       |&lt;br /&gt;
                                      .-.&lt;br /&gt;
                                      | | Pull-up&lt;br /&gt;
                                      | | (10k)&lt;br /&gt;
                                      '-'&lt;br /&gt;
                             MCLR/Vpp  | .-------.&lt;br /&gt;
                                  Pin  +-|       |&lt;br /&gt;
                                       | |  PIC  |&lt;br /&gt;
                                     | o |       |&lt;br /&gt;
                             Reset |=|&amp;gt;  |       |&lt;br /&gt;
                             Taster  | o '-------'&lt;br /&gt;
                                       |&lt;br /&gt;
                                      ===&lt;br /&gt;
                                      GND &lt;br /&gt;
&lt;br /&gt;
Bei externen Oszillatoren bleibt der Pin OSC2 nicht angeschlossen und kann als I/O benutzt werden. Falls ein interner Oszillator benutzt wird, können beide OSC Pins als I/O dienen.&lt;br /&gt;
&lt;br /&gt;
Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungsspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF (0,1 µF) möglichst am kürzesten direkt zwischen VDD und VSS Pins geschaltet.&lt;br /&gt;
&lt;br /&gt;
Folgende Skizzen zeigen die Grundbeschaltung eines PICs:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Pic-entstoer.png|thumb|160px|Entstörkondensator beim PIC]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qz-os.png|thumb|160px|Quarz ]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Qos-os.png|thumb|160px|externer Quarzoszillator]]&lt;br /&gt;
|&lt;br /&gt;
[[Bild:Rc-os.png|thumb|160px|externer RC-Oszillator]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Konfiguration ==&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration eines PICs wird beim &amp;quot;brennen&amp;quot; fest programmiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeiden, muss sie für bestimmten PIC aus einer im MPASM Verzeichnis enthaltenen Datei &amp;quot;PXXFXX.INC&amp;quot; entnommen werden. Die Erklärung der Optionen befindet sich im entsprechenden Datenblatt unter &amp;quot;Special Features of the CPU&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Als Beispiel für PIC16F84 haben wir in der Datei &amp;quot;P16F84.INC&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 ;&lt;br /&gt;
 ;       Configuration Bits&lt;br /&gt;
 ;&lt;br /&gt;
 ;==========================================================================&lt;br /&gt;
 &lt;br /&gt;
 _CP_ON                       EQU     H'000F'&lt;br /&gt;
 _CP_OFF                      EQU     H'3FFF'&lt;br /&gt;
 _PWRTE_ON                    EQU     H'3FF7'&lt;br /&gt;
 _PWRTE_OFF                   EQU     H'3FFF'&lt;br /&gt;
 _WDT_ON                      EQU     H'3FFF'&lt;br /&gt;
 _WDT_OFF                     EQU     H'3FFB'&lt;br /&gt;
 _LP_OSC                      EQU     H'3FFC'&lt;br /&gt;
 _XT_OSC                      EQU     H'3FFD'&lt;br /&gt;
 _HS_OSC                      EQU     H'3FFE'&lt;br /&gt;
 _RC_OSC                      EQU     H'3FFF'&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
 _CP_ON     - Programmspeicher ist vorm Auslesen geschützt&lt;br /&gt;
 _CP_OFF    - Programmspeicher kann ausgelesen werden (ist nicht geschützt)&lt;br /&gt;
 _PWRTE_ON  - Das Programm wird mit Verzögerung von ca. 72 ms nach dem Einschalten gestartet&lt;br /&gt;
 _PWRTE_OFF - Das Programm wird sofort nach dem Einschalten gestartet&lt;br /&gt;
 _WDT_ON    - Watchdog Timer ist aktiv&lt;br /&gt;
 _WDT_OFF   - Watchdog Timer ist unaktiv&lt;br /&gt;
&lt;br /&gt;
Die alle folgende Optionen beziehen sich an den Oszillatortyp:&lt;br /&gt;
&lt;br /&gt;
 _LP_OSC    - Oszillator bis ca. 200 kHz (z.B. Uhrenquarz 32768 Hz)&lt;br /&gt;
 _XT_OSC    - Oszillator bis ca. 3,5 MHz&lt;br /&gt;
 _HS_OSC    - Oszillator über 3,5 MHz (z.B. 4 MHz)&lt;br /&gt;
 _RC_OSC    - Externer RC Oszillator&lt;br /&gt;
&lt;br /&gt;
Die Konfiguration wird im Quellcode (*.asm Datei) mit Direktive &amp;quot;__config&amp;quot; definiert, z.B. so:&lt;br /&gt;
&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Alle Optionen müssen groß geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
Warnung !&lt;br /&gt;
&lt;br /&gt;
Anhand praktischer Erfahrung kann man feststellen, dass bei den kleinsten PICs der Familie 12FXXX, bei dennen ein I/O Pin mit VPP gemultiplext wird (z.B. PIC12F510, PIC12F629, PIC12F635 und 12F675), das Wählen des VPP Pins als I/O verwandelt ihn ins One Time Programming (OTP) Chip, der nur einmal programmiert werden kann. Die gewählte Konfuguration wird entgültig fest &amp;quot;gebrannt&amp;quot; und wegen seitdem fehlender Verbindung des I/O Pins mit VPP keine Umprogrammierung mehr möglich ist. Wer solchen PIC verwenden möchte, sollte aus dem Grund für Entwicklung anderen PIC-Typ nehmen und erst fertiges ausprobiertes Programm einmalig in den für konkrete Anwendung vorgesehenen PIC brennen.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die in der Typenbezeichnung den Buchstaben &amp;quot;C&amp;quot; oder &amp;quot;F&amp;quot; haben.&lt;br /&gt;
&lt;br /&gt;
Die älteren mit &amp;quot;C&amp;quot; haben EPROM Programmspeicher und die gibt es in zwei Versionen: ohne und mit Fenster (aus Quarz-Glass) fürs Löschen des EPROMs mit UV Strahlung. Bei denen ohne Fenster kann der Programmspeicher nur einmal beschrieben und nicht mehr gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Die neuen mit &amp;quot;F&amp;quot; besitzen einen Flash-Programmspeicher, der bis zu 100 000 mal mit angelegter Spannung gelöscht und danach neu beschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:&lt;br /&gt;
 &lt;br /&gt;
- Max. Taktfrequenz des Prozessors.&lt;br /&gt;
&lt;br /&gt;
- Größe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Größe des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, usw.).&lt;br /&gt;
&lt;br /&gt;
- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffähiges Programms, der tatsächlich nötige, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viele Programme für verschiedene PICs entwickelt, wäre der größte PIC16F877 mit 20 MHz max. Taktfrequenz optimal.&lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. &amp;quot;PIC Trainer&amp;quot;) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bißchen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.&lt;br /&gt;
&lt;br /&gt;
= Programm =&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
&lt;br /&gt;
Jedes Programm kann man in kleinere Fragmente unterteilen, die auf bestimmte Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist das s.g. Hautprogramm (kurz:HP), das eine führende Rolle spielt. Dem HP sind fast alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen, um eine bestimmte Aufgabe zu erledigen.&lt;br /&gt;
&lt;br /&gt;
Die Struktur eines Programms ist aber komplizierter, da ein UP auch ein oder mehrere UPs nacheinander aufrufen kann. Ganz unten sind die UP1s, die ganz einfache Sachen erledigen. Höher ist das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, usw. Bei Mid-Range PICs (12FXXX und 16FXXX) können ohne Tricks maximal bis zu 8 Ebenen benutzt werden, da auf dem Stapel (stack) nur max. 8 Rücksprungadressen abgespeichert werden können. Siehe hierzu: [[#Prozessor|Prozessor]] und [[#Programmspeicher|Programmspeicher]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:HP-UP.png|Hauptprogramm - Unterprogramm]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade erledigt werden muss. Weil das nicht egal ist, welches UP aufgerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach Programablaufdiagramm, und nicht chaotisch, abläuft.&lt;br /&gt;
&lt;br /&gt;
Die Programmierung in ASM ist ähnlich wie bei Hochsprachen, wenn man sich Bibliotheken mit geprüften prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren oder einbinden und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Textdatei mit der Endung &amp;quot;.asm&amp;quot; in der vom Assemblerprogramm erwarteten Form verfasst werden, um die fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieser Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogramm zum Übersetzen. Alles was der Assemblerprogramm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss, um die Fehler korrigieren zu können. Eine &amp;quot;.hex&amp;quot; Datei wird erst dann erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen ist es sehr wichtig, sich mit dem Assemblerprogramm vertraut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmablaufdiagramm (PAD)==&lt;br /&gt;
&lt;br /&gt;
Der Programablaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Die Kreativität des Programmierers ist nur für die Erstellung des PADs nötig. Jedes sein Symbol (außer &amp;quot;Start/Stop&amp;quot;) muss als Befehlsreihenfolge für einen bestimmten Prozessor in den Quellcode übertragen werden. Das ist aber nur reine &amp;quot;Übersetzung&amp;quot;. Der Quellcode ist nur eine andere Form des PADs und hoffentlich wird es zukünftig Computerprogramme geben, die ein PAD direkt in eine &amp;quot;*.hex&amp;quot; Datei für bestimmten Prozessor wandeln werden. Zur Zeit muss die &amp;quot;Übersetzung&amp;quot; leider vom Programmierer gemacht werden. Der PAD wird erst dann fertig, wenn nach ihm erstelltes ASM Programm auf einem µC so wie gewünscht funktioniert.&lt;br /&gt;
&lt;br /&gt;
Die Anschriften &amp;quot;Ein&amp;quot; und &amp;quot;Aus&amp;quot; gehören nicht zu Symbolen des PADs und wurden nur zur Erklärung benutzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Der PAD ist sehr einfach zu erstellen, weil dafür nur drei Symbole benötigt sind:&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
[[Bild:PAD_kurz.png|Symbole des PAD]]&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bei PAD Erstellung darf man selbstverständlich beliebige Symbole verwenden, die man selber am besten versteht.  &lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Start/Stopp&amp;quot; Symbol bedeutet, dass das gesamte Programm sich im stabilen Zustand befindet und nicht &amp;quot;läuft&amp;quot;. Anstatt &amp;quot;Stopp&amp;quot; kann auch &amp;quot;Schlaf&amp;quot; (&amp;quot;sleep&amp;quot;) angewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das &amp;quot;Tun&amp;quot; Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das &amp;quot;Prüfen&amp;quot; bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf eines Programms, entweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung.&lt;br /&gt;
&lt;br /&gt;
Als allgemeinnütziges Standard für µCs kann man folgender PAD bezeichnen:&lt;br /&gt;
&lt;br /&gt;
 PAD                                _____&lt;br /&gt;
                                   /     \&lt;br /&gt;
         Spannung ein (Ein) -----&amp;gt;( Start )&lt;br /&gt;
                                   \_____/&lt;br /&gt;
                                      |                   -&lt;br /&gt;
                                      V                    |&lt;br /&gt;
                              .---------------.            |&lt;br /&gt;
                              |Initialisierung|            |&lt;br /&gt;
                              '---------------'            |&lt;br /&gt;
                                      |                    |&lt;br /&gt;
                           .---------&amp;gt;V                    |&lt;br /&gt;
                           |  .---------------.            |&lt;br /&gt;
                           |  | Hauptprogramm |            |&lt;br /&gt;
                           |  '---------------'            |&lt;br /&gt;
                           |          |                    |&lt;br /&gt;
                           |          V                    |&lt;br /&gt;
                           |          A                    |&lt;br /&gt;
                           |         / \                    &amp;gt; Gesamtes Programm &lt;br /&gt;
                           |        /   \                  |&lt;br /&gt;
                           |       /Ende \____             |&lt;br /&gt;
                           |       \  ?  / J  |            |&lt;br /&gt;
                           |        \   /     |            |&lt;br /&gt;
                           |         \ /      |            |&lt;br /&gt;
                           |          V       |            |&lt;br /&gt;
                           |         N|       |            |&lt;br /&gt;
                           `----------´       |            |&lt;br /&gt;
                                              V            |&lt;br /&gt;
                                      .---------------.    |&lt;br /&gt;
                                      |    Beenden    |    |&lt;br /&gt;
                                      '---------------'    |&lt;br /&gt;
                                              |            |&lt;br /&gt;
                                              V           -&lt;br /&gt;
                                            _____&lt;br /&gt;
                                           /     \&lt;br /&gt;
         Spannung aus (Aus) &amp;lt;-------------( Stopp )&lt;br /&gt;
                                           \_____/&lt;br /&gt;
&lt;br /&gt;
Das Hauptprogramm wird in einer endlosen Schleife ausgeführt, die durch die Prüfung &amp;quot;Ende?&amp;quot; unterbrochen werden kann. In dem Fall wird vor dem Beenden des gesamten Programms noch ein UP &amp;quot;Beenden&amp;quot; ausgeführt, das z.B. Daten im EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig, immer die Symbole zu zeichnen, man kann sie sich vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekennzeichnet und die Zeichen &amp;quot;V&amp;quot;, &amp;quot;A&amp;quot;, &amp;quot;&amp;lt;&amp;quot; und &amp;quot;&amp;gt;&amp;quot; zeigen die Richtung des weiteren Verlaufs. Dann sieht der PAD so aus:&lt;br /&gt;
&lt;br /&gt;
                                     Ein &amp;gt; Start&lt;br /&gt;
                                             V                 - &lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |&lt;br /&gt;
                                    |  Hauptprogramm             &amp;gt; Gesamtes Programm&lt;br /&gt;
                                    |        V                  | &lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden    |&lt;br /&gt;
                                    |        N          V      -&lt;br /&gt;
                                    |        V        Stopp &amp;gt; Aus&lt;br /&gt;
                                    `--------´&lt;br /&gt;
&lt;br /&gt;
Man kann auch die unbedeutenden Richtungspfeilen weg lassen:&lt;br /&gt;
&lt;br /&gt;
 PAD1                                Ein &amp;gt; Start               _&lt;br /&gt;
                                      Initialisierung           |&lt;br /&gt;
                                    .-------&amp;gt;V                  |  Gesamtes&lt;br /&gt;
                                    |  Hauptprogramm            |  Programm&lt;br /&gt;
                                    |      Ende? J &amp;gt; Beenden   _|&lt;br /&gt;
                                    |        N        Stopp    &lt;br /&gt;
                                    |        V          V&lt;br /&gt;
                                    `--------´         Aus&lt;br /&gt;
&lt;br /&gt;
In der Praxis werden aus Platzgründen meistens die vereinfachten PADs benutzt.  Als &amp;quot;movxx&amp;quot; wird oft ein Zeichen &amp;quot;-&amp;gt;&amp;quot; benutzt. Zum Beispiel &amp;quot;A-&amp;gt;W&amp;quot; bedeutet, dass der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Außerdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, usw.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, usw.) für logische Operationen angewendet. In den Quellcode werden für diese Zeichen entsprechende Befehle geschrieben. Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                          10h-&amp;gt;W&lt;br /&gt;
                                          W+B-&amp;gt;B&lt;br /&gt;
                                             V&lt;br /&gt;
&lt;br /&gt;
wird im Quellcode so aussehen:&lt;br /&gt;
&lt;br /&gt;
                                        ...........&lt;br /&gt;
                                        movlw   10h&lt;br /&gt;
                                        addwf   B,1&lt;br /&gt;
                                        ...........&lt;br /&gt;
&lt;br /&gt;
Siehe auch: [[#Das erste...|Das erste...]] und [[#Mausrad bzw. Drehencoder|Mausrad bzw. Drehencoder]]&lt;br /&gt;
&lt;br /&gt;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereinfacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogramm beendet werden soll, und das UP &amp;quot;Beenden&amp;quot;, entfallen.&lt;br /&gt;
&lt;br /&gt;
Die meisten ASM Programme für µC sind deswegen nach solchem PAD erstellt:&lt;br /&gt;
&lt;br /&gt;
 PAD2                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |&lt;br /&gt;
                                   .-------&amp;gt;V           |&lt;br /&gt;
                                   |  Hauptprogramm      &amp;gt; Gesamtes Programm&lt;br /&gt;
                                   |        V           |&lt;br /&gt;
                                   `--------´          _|&lt;br /&gt;
                                        &lt;br /&gt;
Für Testprogramme wird meistens folgender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich die CPU schon im Schlaf befindet. Erst dann, darf die Betriebspannung des µCs ausgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
 PAD3                               Ein &amp;gt; Start        _&lt;br /&gt;
                                     Initialisierung    |  Gesamtes&lt;br /&gt;
                                      Hauptprogramm    _|  Programm&lt;br /&gt;
                                          Schlaf &amp;gt; Aus&lt;br /&gt;
&lt;br /&gt;
Und eine batteriebetriebene Uhr wird überwiegend so gestaltet:&lt;br /&gt;
&lt;br /&gt;
 PAD4                               Ein &amp;gt; Start        _&lt;br /&gt;
                       Interrupt     Initialisierung    |&lt;br /&gt;
             Timer-------------------------&amp;gt;V            &amp;gt; Gesamtes Programm&lt;br /&gt;
                                      Hauptprogramm    _|&lt;br /&gt;
                                          Schlaf&lt;br /&gt;
&lt;br /&gt;
In dem Fall reicht es aus, wenn die CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (außer Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es praktisch unmöglich ein PAD zu erstellen, in dem jeder CPU Befehl sein eigenes Symbol hat. Man beschränkt sich nur auf alle Prüfungen, die über den Lauf des Programms entscheiden, und ganze UPs (z.B. &amp;quot;Initialisierung&amp;quot;) nur als ein Symbol verwendet. Für jedes UP wird dann ein eigener PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
Das Erstellen von PAD bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PAD schafft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderungen im ASM Programm verlieren.&lt;br /&gt;
&lt;br /&gt;
Beispiel aus dem Alltag:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Das Programm hat anfangs auf Anhieb funktioniert. Doch leider habe ich dann was geändert was ich nicht mehr weiß. Das Programm macht nun komische Sachen...... Ich kann mir nicht erklären warum, kann mir jemand helfen???&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Für einfache ASM Programme, die gut kommentiert sind, reicht es meistens aus, ein PAD nur &amp;quot;im Kopf&amp;quot; zu erstellen, aber ganz ohne PAD geht es sicher nicht.&lt;br /&gt;
&lt;br /&gt;
Der PAD kann auch benutzt werden, um einen &amp;quot;fremden&amp;quot; Code verständlich zu machen. In dem Fall werden alle Befehle (Zeilen) aus dem Quellcode nacheinander in PAD Symbole umgewandelt und daraus ein PAD erstellt.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogramm das wichtigste Teil des gesamten Programms. Meistens ist es auch das kleinste Teil, vor allem, wenn die UPs sehr komplex sind. Seine Aufgabe ist die benötigte UPs in bestimmter Reihenfolge nacheinander aufzurufen, um die alle Funktionen des gesamten Programms zu realisieren. &lt;br /&gt;
&lt;br /&gt;
Das HP ist meistens als endlose Schleife, wie im PAD2, aufgebaut. Weil die endlose Schleife sehr schnell läuft, werden alle durch die UPS realisierten Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden. Dafür können auch UPs mit fester Ausführungszeit (z.B. Displayausgabe) angewendet werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PAD für ein HP sieht so aus:&lt;br /&gt;
&lt;br /&gt;
                                      Haupt    .---&amp;gt;V&lt;br /&gt;
                                               |   UP1&lt;br /&gt;
                                               |   UP2&lt;br /&gt;
                                               |   ...&lt;br /&gt;
                                               |   UPn&lt;br /&gt;
                                               |    V&lt;br /&gt;
                                               `----´&lt;br /&gt;
&lt;br /&gt;
In den Quellcode wird es so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Haupt   call    UP1	&lt;br /&gt;
                                             call    UP2&lt;br /&gt;
                                             ...........&lt;br /&gt;
                                             call    UPn&lt;br /&gt;
                                             goto    Haupt&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird das HP schrittweise erstellt. Am Anfang wird sich nur ein Aufruf vom UP im HP befinden und die folgenden kommen nach Erstellung und Prüfen weiteren UPs dazu, bis das HP fertig wird.&lt;br /&gt;
&lt;br /&gt;
== Unterprogramm ==&lt;br /&gt;
&lt;br /&gt;
Unterprogramm wird durch übergeordnetes Programmteil (Aufrufer) mit &amp;quot;call&amp;quot; aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer in die Zeile nach dem &amp;quot;call&amp;quot; gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; Befehl, der sich am Ende jedes UPs befinden muss, erreicht. Und das ist der einzige Unterschied zwischen einem HP und einem UP.&lt;br /&gt;
&lt;br /&gt;
Jedes UP hat folgender PAD:&lt;br /&gt;
&lt;br /&gt;
                                vom Aufrufer ------------&amp;gt;V&lt;br /&gt;
                                                         Tun&lt;br /&gt;
                                                          V&lt;br /&gt;
                         zurück zum Aufrufer &amp;lt;----------return bzw. retlw &lt;br /&gt;
&lt;br /&gt;
Bei dem Rückkehr aus dem UP mit &amp;quot;retlw&amp;quot; befindet sich im W-Register der Wert aus dem Befehl &amp;quot;retlw&amp;quot;. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt und ermöglicht eventuelle Fehler beim Ausführung des Programmteils zu erkennen.&lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Programm als UP benutzt werden, wenn der sich am Ende des HPs befindlicher Befehl &amp;quot;goto&amp;quot; durch &amp;quot;return&amp;quot; ersetzt wird. Ein Beispiel dazu:&lt;br /&gt;
&lt;br /&gt;
             Haupt1  call    UP11                          Haupt1  call    UP11&lt;br /&gt;
                     call    UP21                                  call    UP21&lt;br /&gt;
                     ...........             -------&amp;gt;              ...........&lt;br /&gt;
                     call    UPn1                                  call    UPn1 &lt;br /&gt;
                     goto    Haupt1                                return &lt;br /&gt;
&lt;br /&gt;
Jetzt können wir im mehr komplexen HP (Haupt) das Haupt1 als Unterprogramm aufrufen:&lt;br /&gt;
&lt;br /&gt;
                                   Haupt    call    UP1      &lt;br /&gt;
                                            call    Haupt1&lt;br /&gt;
                                            ...........&lt;br /&gt;
                                            call    UPn&lt;br /&gt;
                                            goto    Haupt&lt;br /&gt;
&lt;br /&gt;
Jedes UP kann auch von einem anderen übergeordneten UP aufgerufen werden, wenn das was es realisiert, benötigt wird.&lt;br /&gt;
&lt;br /&gt;
In der Praxis wird oft ein UP von mehreren anderen UPs benutzt. Zum Beispiel um LCD Display zu steuern, brauchen wir entweder ein Befehl (Cmd) oder ein Zeichen (Data) an Display zu schicken. In beiden Fällen wird ein Byte geschickt, einmal mit RS=0 (Befehl) und einmal mit RS=1 (Zeichen) laut folgendem PAD:&lt;br /&gt;
&lt;br /&gt;
                                        &amp;quot;Cmd&amp;quot;   &amp;quot;Data&amp;quot; &lt;br /&gt;
                                         RS=0    RS=1&lt;br /&gt;
                                          V       V &lt;br /&gt;
                                          `--&amp;gt;V&amp;lt;--´&lt;br /&gt;
                                    &amp;quot;Send&amp;quot; Byte schicken&lt;br /&gt;
                                              V&lt;br /&gt;
                                            return&lt;br /&gt;
&lt;br /&gt;
Das wird in den Quellcode z.B. so eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                     Cmd     bcf     RS&lt;br /&gt;
                                             goto    Send&lt;br /&gt;
                                     Data    bsf     RS&lt;br /&gt;
                                     Send    ............&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Send&amp;quot; ist den UPs &amp;quot;Cmd&amp;quot; und &amp;quot;Data&amp;quot; untergeordnet, da es von beiden benutzt wird, kann aber weder &amp;quot;Cmd&amp;quot; noch &amp;quot;Data&amp;quot; benutzen.&lt;br /&gt;
&lt;br /&gt;
=== Initialisierung ===&lt;br /&gt;
&lt;br /&gt;
Damit der PIC ein Programm ausführen kann, muss er vollständig und richtig konfiguriert und initialisiert werden. Deswegen als erstes UP, das von dem gesamten Programm noch vor dem HP aufgerufen wird , ist &amp;quot;Initialisierung&amp;quot; (kurz: Init)&lt;br /&gt;
&lt;br /&gt;
==== Variablen ====&lt;br /&gt;
&lt;br /&gt;
Weil sich nach dem Einschalten der Spannung im RAM zufällige Werte befinden, wird oft als erstes der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife erledigt, die indirekte Adressierung verwendet:&lt;br /&gt;
&lt;br /&gt;
                                                   V&lt;br /&gt;
                             Adresse des ersten Registers in FSR laden (20h)&lt;br /&gt;
                             .--------------------&amp;gt;V&lt;br /&gt;
                  RAMClr     |Indirekt adressierter Register löschen (INDF)&lt;br /&gt;
                             |              Adresse erhöhen&lt;br /&gt;
                             |        Letzte Adresse + 1 = 80h J &amp;gt; Return&lt;br /&gt;
                             |                     N&lt;br /&gt;
                             |                     V&lt;br /&gt;
                             `---------------------´&lt;br /&gt;
&lt;br /&gt;
Es wird wie folgt in Quellcode eingeschrieben:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                   RAMClr ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    RAMClr&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Um Anzahl den Marken (label) zu verringern, wird oft ein Symbol &amp;quot;$&amp;quot; benutzt. Es bedeutet die Adresse der aktuellen Befehlszeile. Es kann also auch so geschrieben werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x20&lt;br /&gt;
                                             movwf   FSR&lt;br /&gt;
                                          ,-&amp;gt;clrf    INDF&lt;br /&gt;
                                          |  incf    FSR,1&lt;br /&gt;
                                          |  btfss   FSR,7&lt;br /&gt;
                                          `-&amp;lt;goto    $-3   ; springe zu aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigten Variablen die gewünschten Werte zugewiesen werden:&lt;br /&gt;
&lt;br /&gt;
                                             movlw   0x3C&lt;br /&gt;
                                             movwf   LimH&lt;br /&gt;
                                             movlw   0x5A&lt;br /&gt;
                                             movwf   LimL&lt;br /&gt;
                                             u.s.w.&lt;br /&gt;
&lt;br /&gt;
Somit sind die Variablen initialisiert.&lt;br /&gt;
&lt;br /&gt;
==== I/O Ports ====&lt;br /&gt;
&lt;br /&gt;
Nach dem Einschalten der Spannung sind die für Komparatoren oder A/D Wandler benutzte Pins als analoge Eingänge initialisiert.  Wenn sie alle als digitale I/Os verwendet werden sollen, müssen sie als solche definiert werden. Das geschieht durch Schreiben des Wertes 7 in das entsprechende Register (CMCON bzw. ADCON1):&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                bzw.             movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als analoge Eingänge benutzt werden sollen, müssen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden in alle Ports nacheinander die gewünschte Werte die an den Pins vor dem Start des Hauptprogramms ausgegeben werden sollen, geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       clrf    PORTA&lt;br /&gt;
                                       movlw   0x37&lt;br /&gt;
                                       movwf   PORTB &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anschließend werden für jeden Port die Werte in TRISx Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRISx Register durch 1 als Eingang und durch 0 als Ausgang definiert. Beispielweise beim PORTB sollen B7,B5 und B3 als Eingänge und restliche Pins als Ausgänge definiert werden. Das ergibt den Wert 10101000b = A8h, der in den TRISB Register geschrieben werden muss. Weil die alle TRISx Register sich in der höheren Bank befinden, muss im STATUS-Register auf entsprechende Bank und danach zurück auf Bank 0 umgeschaltet werden. Zum Beispiel für die TRISB in der Bank1:&lt;br /&gt;
&lt;br /&gt;
                                       bsf     STATUS,RP0&lt;br /&gt;
                                       movlw   0xA8&lt;br /&gt;
                                       movwf   TRISB&lt;br /&gt;
                                       bcf     STATUS,RP0&lt;br /&gt;
&lt;br /&gt;
Bei einem Umschalten der Bank können selbstverständlich alle TRISx Register, die in der gleichen Bank liegen, nacheinander beschrieben werden. Siehe : [[#PORTx|PORTx]] und [[#TRISx|TRISx]]&lt;br /&gt;
&lt;br /&gt;
Bei dem PORTA gibt es Pins, die nur &amp;quot;open drain&amp;quot; Ausgang haben (können nur auf GND schalten) bzw. nur als Eingang benutzt werden können. Bei Planung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplante Anwendung eignet.&lt;br /&gt;
&lt;br /&gt;
==== Hardware ====&lt;br /&gt;
&lt;br /&gt;
Die für ASM Programm benutzte Hardware kann auf integrierte und externe geteilt werden. Für eine Initialisierung der integrierten Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, usw.), müssen entsprechende SFRs (Spezial Function Registers) laut Datenblatt des PICs definiert werden.&lt;br /&gt;
&lt;br /&gt;
Die externe Hardware muss nach Datenblättern der Hersteller initialisiert werden.&lt;br /&gt;
&lt;br /&gt;
=== Einlesen ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit von einem Portpin einzulesen und in ein bestimmtes Register zu Kopieren wird folgender PAD benutzt, weil ein PIC kein Befehl dafür hat:&lt;br /&gt;
&lt;br /&gt;
                                            V&lt;br /&gt;
                                   Quellbit = 0 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister löschen |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
                                   Quellbit = 1 ? N &amp;gt;------.&lt;br /&gt;
                                            J              |&lt;br /&gt;
                                            V              |&lt;br /&gt;
                               Bit im Zielregister setzen  |&lt;br /&gt;
                                            V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
Wenn wir z.B. ein bit3 von PortA als bit1 in den Register Tasten kopieren wollen, dann wird es in Quellcode so geschrieben:&lt;br /&gt;
&lt;br /&gt;
                                       btfss   PORTA,3&lt;br /&gt;
                                       bcf     Tasten,1&lt;br /&gt;
                                       btfsc   PORTA,3&lt;br /&gt;
                                       bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn es zulässig ist, dass sich das Bit im Zielregister kurzzeitig ändert, kann man sich die erste Zeile im Quellcode ersparen:&lt;br /&gt;
                                             V&lt;br /&gt;
                                Bit im Zielregister löschen&lt;br /&gt;
                                    Quellbit = 0 ? J &amp;gt;------.&lt;br /&gt;
                                             N              |&lt;br /&gt;
                                             V              |&lt;br /&gt;
                                Bit im Zielregister setzen  |&lt;br /&gt;
                                             V&amp;lt;-------------´&lt;br /&gt;
&lt;br /&gt;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Wenn ein ganzes Byte vom Port in das W-Register eingelesen wird, kann man den Wert gleich komplett in das Zielregister schreiben:&lt;br /&gt;
&lt;br /&gt;
                                        movf     PORTA,0&lt;br /&gt;
                                        movwf    Tasten&lt;br /&gt;
&lt;br /&gt;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmter Bit mit &amp;quot;bcf&amp;quot; gelöscht oder mit &amp;quot;bsf&amp;quot; gesetzt. Zum Beispiel bit4 im PORTA:&lt;br /&gt;
&lt;br /&gt;
                                        bcf   PORTA,4.&lt;br /&gt;
&lt;br /&gt;
Um ein Byte auszugeben wird es zuerst in das W-Register geladen und danach an den Port übergeben, z.B.:&lt;br /&gt;
&lt;br /&gt;
                                        movlw  0x12&lt;br /&gt;
                                        movwf  PORTA&lt;br /&gt;
&lt;br /&gt;
=== Schleifen ===&lt;br /&gt;
&lt;br /&gt;
Ein in ASM Programmen meist verbreitetes Codefragment ist eine Schleife.&lt;br /&gt;
&lt;br /&gt;
Es kann eine endlose Schleife, die durch Prüfung einer bestimmten Bedingung (z.B. Taste) unterbrochen wird, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&amp;lt;-----.&lt;br /&gt;
                                            Tun     |&lt;br /&gt;
                                             ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter&lt;br /&gt;
&lt;br /&gt;
Es kann eine Schleife mit Schleifenzähler (z.B. Temp), die bestimmte Anzahl Durchläufe hat, sein:&lt;br /&gt;
&lt;br /&gt;
                                             V&lt;br /&gt;
                                   Anzahl ins Temp laden  &lt;br /&gt;
                                             V&amp;lt;---------. &lt;br /&gt;
                                            Tun         |&lt;br /&gt;
                                   Temp decrementieren  |   &lt;br /&gt;
                                        Temp = 0 ? N &amp;gt;--´&lt;br /&gt;
                                             J&lt;br /&gt;
                                             V&lt;br /&gt;
                                           weiter &lt;br /&gt;
                                                                                       &lt;br /&gt;
Solche Schleifen können als UPs verwendet werden, wenn &amp;quot;weiter&amp;quot; mit &amp;quot;return&amp;quot; ersetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das waren Beispiele für Schleifen, die bewusst programmiert sind. Es gibt leider auch endlose Schleifen, die durch einen Fehler im Programm enstanden sind und zum &amp;quot;hängen&amp;quot; des Programms führen. Solche Schleifen sind im Programm nicht einfach zu finden, da ihre Parameter unbekannt sind. In dem Fall sehr behilflich ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
=== Pause ===&lt;br /&gt;
&lt;br /&gt;
Um eine Pause (Warten, Verzögerung) im Programm anzulegen wird der &amp;quot;nop&amp;quot; Befehl benutzt, während dessen Ausführung der CPU nichts macht. Mit einem &amp;quot;nop&amp;quot; kann eine Zeit gleich 4 Takten (Perioden) des Oszillators realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr kurze Wartezeiten benutzt man eine Reihe von nachfolgenden &amp;quot;nop&amp;quot;s. Beim einem Oszillator 4 MHz, die Ausführungszeit des Prozessors beträgt 1 µs pro &amp;quot;nop&amp;quot;. Wenn z.B. 4 µs benötigt werden, werden dafür 4 &amp;quot;nop&amp;quot;s gebraucht:&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        nop&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Das gleiche bewirken 2 &amp;quot;goto&amp;quot;s, brauchen aber im Vergleich zu &amp;quot;nop&amp;quot;s nur die Hälfte der Bytes im Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                        ...&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        goto $+1&lt;br /&gt;
                                        ...&lt;br /&gt;
&lt;br /&gt;
Der Befehl goto $+1 bedeutet &amp;quot;springe zur aktuellen Adresse + 1&amp;quot; (also nächster Adresse) und seine Ausführungszeit ist gleich 2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Für kurze Zeiten werden s.g. Warteschleifen, wie im folgendem PAD benutzt:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
In Quellcode wird es als UP so eigeschrieben:    &lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop &lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0      &lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Der Sprung zur Marke &amp;quot;Warte0&amp;quot; (&amp;quot;goto Warte0&amp;quot;) wurde in rechtem Beispiel durch &amp;quot;goto $-1&amp;quot; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = 3 * P0 + 6 + n   &lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P0 * ( 4 / Fosc ) &lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, 6 = Ausführungszeit von &amp;quot;call&amp;quot; (2) + &amp;quot;movlw&amp;quot; (1) + &amp;quot;movwf&amp;quot; (1) + &amp;quot;return&amp;quot; (2), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Wenn in ein Register PX eine 0 eingeschrieben wird, bedeutet es, dass die decrementierung des Registers 100h = 256d Takten dauern wird, da dekrementierte 0 eine FFh = 255d ergibt. Deshalb in Warteschleifen ist die Zahl 0 die grösste (256 Dürchläufe) und 1 die kleinste. Für solche einfache Schleifen (als UP) die Wartezeit beträgt min. 9 und max. ca. 800 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für mittlere Wartezeiten z.B. 0,1 Sekunde werden doppelte Warteschleifen verwendet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P1 laden&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.&lt;br /&gt;
                                       P0 laden         |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |&lt;br /&gt;
                                 P0 decrementieren  |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |&lt;br /&gt;
                                         J              |&lt;br /&gt;
                                         V              |&lt;br /&gt;
                                 P1 dekrementieren      |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
 &lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Wie vorher wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
&lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P1 * (3 * P0 + 5) + 8 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T =  N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, 8 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 2 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche doppelte Schleifen (als UP) die Wartezeit beträgt min. 16 und max. ca. 200 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Für lange Wartezeiten z.B. 1 Sekunde werden 3-fache Warteschleifen angewendet.&lt;br /&gt;
&lt;br /&gt;
Solche Warteschleife ist im folgenden PAD abgebildet:&lt;br /&gt;
&lt;br /&gt;
                         Warte           V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                       P2 laden&lt;br /&gt;
                         Warte2          V&amp;lt;-----------------.&lt;br /&gt;
                                       P1 laden             |&lt;br /&gt;
                         Warte1          V&amp;lt;-------------.   |&lt;br /&gt;
                                       P0 laden         |   |&lt;br /&gt;
                         Warte0          V&amp;lt;---------.   |   |&lt;br /&gt;
                                 P0 decrementieren  |   |   |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´   |   |&lt;br /&gt;
                                         J              |   |&lt;br /&gt;
                                         V              |   |&lt;br /&gt;
                                 P1 decrementieren      |   |&lt;br /&gt;
                                      P1 = 0 ? N &amp;gt;------´   |&lt;br /&gt;
                                         J                  |&lt;br /&gt;
                                         V                  |&lt;br /&gt;
                                 P2 dekrementieren          |&lt;br /&gt;
                                      P2 = 0 ? N &amp;gt;----------´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Das wird in Quellcode als UP so aussehen:&lt;br /&gt;
&lt;br /&gt;
              Warte     nop                        Warte     nop&lt;br /&gt;
                        ...                                  ...&lt;br /&gt;
                        nop                                  nop&lt;br /&gt;
                        movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P2                           movwf   P2&lt;br /&gt;
              Warte2    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P1                           movwf   P1 &lt;br /&gt;
              Warte1    movlw   0xXX                         movlw   0xXX&lt;br /&gt;
                        movwf   P0                           movwf   P0&lt;br /&gt;
              Warte0    decfsz  P0,1                         decfsz  P0,1&lt;br /&gt;
                        goto    Warte0                       goto    $-1&lt;br /&gt;
                        decfsz  P1,1                         decfsz  P1,1&lt;br /&gt;
                        goto    Warte1                       goto    $-5&lt;br /&gt;
                        decfsz  P2,1                         decfsz  P2,1 &lt;br /&gt;
                        goto    Warte2                       goto    $-9&lt;br /&gt;
                        return                               return&lt;br /&gt;
&lt;br /&gt;
Auch hier wurden rechts die Marken durch &amp;quot;$-n&amp;quot; ersetzt. &lt;br /&gt;
   							 &lt;br /&gt;
Die gesammte Anzahl den CPU Takten (N) lässt sich aus folgender Formel berechnen:&lt;br /&gt;
&lt;br /&gt;
N = P2 * [ P1 * (3 * P0 + 5) + 9 ] + 10 + n&lt;br /&gt;
&lt;br /&gt;
und die Wartezeit (T) in Sekunden:&lt;br /&gt;
&lt;br /&gt;
T = N * ( 4 / Fosc ), für Schätzungen T ~ 3 * P2 * P1 * P0 * ( 4 / Fosc )&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
P0 = Zahl im Register P0, P1 = Zahl im Register P1, P2 = Zahl im Register P2, 10 = Ausführungszeit von &amp;quot;call&amp;quot; + &amp;quot;return&amp;quot; + 3 * (&amp;quot;movlw&amp;quot; + &amp;quot;movwf&amp;quot;), n = Anzahl &amp;quot;nop&amp;quot;s, Fosc = Frequenz des Oszillators (z.B. Quartz)&lt;br /&gt;
&lt;br /&gt;
Für solche 3-fache Schleifen (als UP) die Wartezeit beträgt min. 27 und max. ca. 50 000 000 Prozessortakten (ohne &amp;quot;nop&amp;quot;s). &lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;nop&amp;quot;s vor allen Warteschleifen sind nur notwendig um genaue Wartezeit einzustellen zu können. Sie können auch mit &amp;quot;goto $+1&amp;quot;s ersetzt, oder weg gelassen werden. Sie können auch innerhalb jeder Schleife eingesetzt werden, um sie deutlich zu verlängern.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
                                         V&lt;br /&gt;
                                       n * nop&lt;br /&gt;
                                      P0 laden&lt;br /&gt;
                                         V&amp;lt;---------.&lt;br /&gt;
                                      n0 * nop &lt;br /&gt;
                                 P0 decrementieren  |&lt;br /&gt;
                                      P0 = 0 ? N &amp;gt;--´&lt;br /&gt;
                                         J&lt;br /&gt;
                                         V&lt;br /&gt;
&lt;br /&gt;
Bei nur einem &amp;quot;nop&amp;quot; (n0=1) ist die max. Wartezeit ca. T ~ 4 * P0 * ( 4 / Fosc ), bei zwei (n0=2) ca. T ~ 5 * P0 * ( 4 / Fosc ) usw. &lt;br /&gt;
&lt;br /&gt;
Anstatt &amp;quot;movlw   0xXX&amp;quot; kann auch &amp;quot;movf  PauseX,0&amp;quot; angewendet werden, wenn die Schleife mehrmals mit verschiedenen Werten P0, P1 und P2 aus den Register Pause0, Pause1 und Pause2 benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Für sehr lange Wartezeiten können, nach gleichem Prinzip, Warteschleifen erstellt werden, die mehr als 3 Schleifen enthalten.&lt;br /&gt;
&lt;br /&gt;
In zeitkritischen ASM Programmen werden anstatt Warteschleifen (z.B. für Tastenenentprellung) zusammengesetzte UPs mit benötigter Ausführungszeit (z.B. Frequenzmessung + Displayausgabe + ...) angewendet.&lt;br /&gt;
&lt;br /&gt;
=== Tabellen ===&lt;br /&gt;
&lt;br /&gt;
Es gibt zwei Arten von Tabellen: Sprungtabellen (computed goto) die &amp;quot;goto&amp;quot; Befehle enthalten und Wertetabellen (lookup table) in denen feste Werte in &amp;quot;retlw&amp;quot; gespeichert sind. Der wichtigste Unterschied zwischen denen ist, dass die Sprungtabellen steuern den Programmlauf abhängig vom Inhalt des W-Registers und  die Wertetabellen liefern abhängig von Inhalt des W-Registers ein Wert an den Aufrufer zurück. &lt;br /&gt;
&lt;br /&gt;
Beide werden in Programmspeicher erstellt. Sie können nur bis zu 256 Speicherstellen belegen, da in den W-Register auch nur so viel verschiedenen Zahlen &amp;quot;passen&amp;quot;. Sie Fangen also (fast) immer bei einer Adresse XX00h an und enden bei XXFFh. Der Hochwertige Byte &amp;quot;XX&amp;quot; der Adresse an der sich der Anfang einer Tabelle befindet, muss vor dem Einsprung in die Tabelle ins PCLATH Register eingeschrieben werden, wenn die Tabelle weit vom Aufrufer liegt. In der Praxis werden solche Tabellen am oberen Ende des Programmspeichers angelegt, damit sie den ASM Code nicht unterbrechen.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     goto   Marke0&lt;br /&gt;
                              XX01     goto   Marke1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     goto   Marke254&lt;br /&gt;
                              XXFF     goto   Marke255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
Wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert, der die Wahl wohin gesprungen wird bestimmt.&lt;br /&gt;
&lt;br /&gt;
Nach ausführen der obiger Befehlsfolge, wird das ASM Programm z.B. für Twert=0x01 weiter ab Marke1 &amp;quot;laufen&amp;quot; bis es an &amp;quot;return&amp;quot; kommt. Dann springt es zurück zum Aufrufer der Tabelle.&lt;br /&gt;
&lt;br /&gt;
Eine Sprungtabelle kann auch mit &amp;quot;goto&amp;quot; eingesprungen werden, dann wird aber beim Erreichen des &amp;quot;return&amp;quot;s bis zum letzten &amp;quot;call&amp;quot; zurückgesprungen.  Siehe hierzu auch [[#PIC Trainer|PIC Trainer]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Eine Wertetabelle wird so aufgebaut:&lt;br /&gt;
&lt;br /&gt;
                                 org  (XX-1)FF &amp;lt;--- eine Direktive für Assemblerprogramm, wo es &lt;br /&gt;
                                                    die Tabelle im Programmspeicher plazieren soll&lt;br /&gt;
                           Adresse     Inhalt&lt;br /&gt;
                           -------------------------                      &lt;br /&gt;
                 Tab1     (XX-1)FF     addwf  PCL,1&lt;br /&gt;
                              XX00     retlw  Wert0&lt;br /&gt;
                              XX01     retlw  Wert1&lt;br /&gt;
                              .......................&lt;br /&gt;
                              XXFE     retlw  Wert254&lt;br /&gt;
                              XXFF     retlw  Wert255&lt;br /&gt;
&lt;br /&gt;
Und so aufgerufen:&lt;br /&gt;
&lt;br /&gt;
                              movlw    0xXX&lt;br /&gt;
                              movwf    PCLATH&lt;br /&gt;
                              movf     TWert,0&lt;br /&gt;
                              call     Tab1&lt;br /&gt;
&lt;br /&gt;
wobei:&lt;br /&gt;
&lt;br /&gt;
0xXX = Hochwertiger Byte der Adresse von Tab1, TWert = ein Wert im W-Register, für welchen, an den Aufrufer bestimmter Wert aus der Tabelle im W-Register zurückgeliefert wird.&lt;br /&gt;
&lt;br /&gt;
Wertetabelle kann auch mit Hilfe der MPASM Direktive &amp;quot;dt&amp;quot; erstellt werden. So kann man sich  mehrfaches Schreiben von &amp;quot;retlw&amp;quot; Befehlen ersparen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x(XX-1)FF&lt;br /&gt;
 Tabelle         addwf  PCL,1 &lt;br /&gt;
                                                    ; nachfolgend der benötigte Wert im W- Register&lt;br /&gt;
                                                    ; vor dem Aufruf der Tabelle&lt;br /&gt;
 	dt      3, 0xE8                            ; 0x00&lt;br /&gt;
 	dt      5, 0xB7                            ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0                      ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0          ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0      ; 0x0F&lt;br /&gt;
 	dt      'C','=',0                          ; 0x17&lt;br /&gt;
 	dt      'L','=',0                          ; 0x1A&lt;br /&gt;
 	dt      'F','=',0                          ; 0x1D&lt;br /&gt;
 	dt      'O','K',0                          ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechendem Wert im W-Register (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0 (Null) enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
=== Interrupt ===&lt;br /&gt;
&lt;br /&gt;
==== Prinzip ====&lt;br /&gt;
&lt;br /&gt;
Ein Interrupt (Unterbrechung) unterbricht ein laufendes Programm, wenn ein bestimmtes Ereigniss, auf das reagiert werden soll, statt gefunden hat. Die Reaktion wird in s.g. Interrupt Service Routine (kurz: ISR) definiert.&lt;br /&gt;
&lt;br /&gt;
Einfach gesagt, ein Interrupt stoppt ein laufendes Programm nach dem Ausführen der aktuellen Zeile, ruft die ISR auf und nach deren Ausführung startet das Programm wieder, ab der Zeile, vor der es durch Interrupt angehalten wurde. &lt;br /&gt;
&lt;br /&gt;
                                                .---&amp;gt;V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                   Interrupt ------&amp;gt;Tun--------&amp;gt;V&lt;br /&gt;
                                                |    V         ISR&lt;br /&gt;
                                                |   Tun&amp;lt;--------´&lt;br /&gt;
                                                |    V&lt;br /&gt;
                                                |   Tun&lt;br /&gt;
                                                |    V &lt;br /&gt;
                                                `----´&lt;br /&gt;
&lt;br /&gt;
Damit das unterbrochene Programm nach dem Rückkehr aus der ISR weiter fehlerfrei ausgeführt werden kann, darf die ISR keine Änderungen in vom Programm benutzten Register verursachen.&lt;br /&gt;
Deswegen wenn UPs aus dem Programm durch ISR benutzt werden, müssen alle Register, dessen Inhalt durch ISR geändert wird, vor dem Ausführen der ISR (als ersten Befehle der ISR nach dem &amp;quot;bcf INTCON,GIE&amp;quot;) im RAM gespeichert und nach der Ausführung der ISR (vorm &amp;quot;retfie&amp;quot;) wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er vorher, durch beschreiben nötigen Register (INTCON, PIR, usw.) vorbereitet werden. Siehe hierzu: [[#INTCON|INTCON]] und [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
==== Quellen ====&lt;br /&gt;
&lt;br /&gt;
Es gibt folgende Interrupt-Quellen:&lt;br /&gt;
&lt;br /&gt;
- interne Hardware (z.B. ein Timer)&lt;br /&gt;
&lt;br /&gt;
- externe Hardware (z.B. eine Taste)&lt;br /&gt;
&lt;br /&gt;
Die alle PICs der Mid-Range Familie haben im Programmspeicher nur eine Adresse (s.g. Interrupt Vektor 0x0004), wohin im Falle eines Interrupts, gesprungen wird. Um ermöglichen den Verursacher des Interrupts zu finden, hat jede Quelle ein eigenes Interrupt Flag (IF), das gesetzt wird, wenn das Interrupt ausgelöst wird. Somit kann in der ISR nach der Prüfung der IFs auf jeden Interrupt gezielt reagiert werden. Siehe hierzu: [[#Interrupts|Interrupts]].&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das für Basic-Line und Mid-Range immer an der Adresse 0x0004 beginnt und immer mit dem Befehl &amp;quot;retfie&amp;quot; endet. Ihr Umfang ist von der Menge der Quellen und der Reaktionen auf ihre Interrupts abhängig. Folgender PAD zeigt ein allgemeiner Aufbau der ISR:&lt;br /&gt;
&lt;br /&gt;
                                         org 0x0004&lt;br /&gt;
                                     Interrupts sperren            ; bcf   INTCON,GIE&lt;br /&gt;
                                Beeinflüsste Register sichern&lt;br /&gt;
                                 Interrupt-Quelle ermitteln&lt;br /&gt;
                                   Interrupt-Flag löschen&lt;br /&gt;
                                 und entsprechend reagieren&lt;br /&gt;
                             Beeinflüsste Register restaurieren&lt;br /&gt;
                                zurück ins Programm springen       ; retfie&lt;br /&gt;
&lt;br /&gt;
Je nach Bedürfnissen, wird eine ISR nur nötige Elemente davon enthalten. Um auf alle Interrupts reagieren zu können muss die ISR vor dem nächsten Interrupt beendet werden. Da das Programm nur in den Pausen zwischen Ausführungen der ISR laufen kann, sollte die Ausführungszeit der ISR möglichst kurz sein.  					    &lt;br /&gt;
                                     &lt;br /&gt;
Die kürzeste ISR setzt nur ein Flag (&amp;quot;_Fint&amp;quot;), das dem Programm zeigt, dass ein Interrupt statt gefunden hat. Sie eignet sich für den Fall, wenn nur eine Interrupt-Quelle erlaubt ist. Das Programm wird für nur 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                                         org     0x0004&lt;br /&gt;
                                         bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bcf     IF                ; Interrupt Flag löschen&lt;br /&gt;
                                         bsf     _Fint             ; Flag setzen&lt;br /&gt;
                                         retfie                    ; zurück ins Programm&lt;br /&gt;
&lt;br /&gt;
Das Programm prüft das Flag &amp;quot;_Fint&amp;quot;, löscht es und reagiert entsprechend. Somit kann ein Interrupt im Hauptprogramm bearbeitet werden. &lt;br /&gt;
&lt;br /&gt;
Die ISR kann aber auch ein HP darstellen. Siehe hierzu: [[#Interrupts|Interrupts]]&lt;br /&gt;
&lt;br /&gt;
=== Schnittstellen und Treiber ===&lt;br /&gt;
&lt;br /&gt;
Als Schnittstelle wird externe Hadware, die zum Steuern eines an sie angeschlossenes &amp;quot;Gerätes&amp;quot; (z.B. eines Displays) dient, genannt. Das ASM Programmteil, das die Steuerung ermöglicht ist ein Treiber. Als Beispiele siehe: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]] und [http://www.roboternetz.de/phpBB2/viewtopic.php?t=22749]&lt;br /&gt;
&lt;br /&gt;
== Vorlage für MPASM ==&lt;br /&gt;
&lt;br /&gt;
Diese Vorlage ist nur für ASM Programme ohne Interrupts geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw.&lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Die Variablen können auch kürzer mit s.g. cblock definiert werden:&lt;br /&gt;
&lt;br /&gt;
 cblock 0x20 &lt;br /&gt;
 SecondL&lt;br /&gt;
 SecondH&lt;br /&gt;
 MinuteL&lt;br /&gt;
 MinuteH&lt;br /&gt;
 StundeL&lt;br /&gt;
 StundeH&lt;br /&gt;
 endc&lt;br /&gt;
&lt;br /&gt;
Bei sehr vielen Variablen sind aber die Registeradressen nicht so übersichtlich.&lt;br /&gt;
&lt;br /&gt;
Für Programme mit Interrupts ist diese Vorlage geeignet:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration&lt;br /&gt;
 #define	_DTT1	GPIO,0			; Portpins benennen&lt;br /&gt;
 #define	_CKT2	GPIO,1&lt;br /&gt;
 #define	_T3	GPIO,2&lt;br /&gt;
 #define	_RNG	GPIO,3&lt;br /&gt;
 #define	_INT	GPIO,4&lt;br /&gt;
 #define	_RL	GPIO,5&lt;br /&gt;
         usw. &lt;br /&gt;
 SecondL	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 SecondH	equ	0x21&lt;br /&gt;
 MinuteL	equ	0x22&lt;br /&gt;
 MinuteH	equ	0x23&lt;br /&gt;
 StundeL equ	0x24&lt;br /&gt;
 StundeH equ	0x25&lt;br /&gt;
         usw.&lt;br /&gt;
 		org 	0x0000		; bis da sind MPASM Direktiven&lt;br /&gt;
                                         ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
                 call	Init		; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
                 goto    Haupt           ; gehe zum Hauptprogramm &amp;quot;Haupt&amp;quot; &lt;br /&gt;
                 org     0x004           ; hier fängt die ISR (interrupt service routine) an&lt;br /&gt;
                 bcf     INTCON,GIE      ; interrupts sperren&lt;br /&gt;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR, interrupts wieder erlauben&lt;br /&gt;
 Haupt		............		; hier fängt das Hauptprogramm als endlose Schleife an&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		goto	Haupt		; hier endet das HP, gehe zum Anfang des HPs (zurück)&lt;br /&gt;
 UP1		............		; Unterprogramme&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 		############&lt;br /&gt;
 UPn		............&lt;br /&gt;
 		Eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	GPIO		; lösche Port&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		call	0x3FF		; hole Kalibrationswert&lt;br /&gt;
 		movwf	OSCCAL		; kalibriere internen RC oscillator&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x38		; definiere Portpins GPIO, (z.B. 0-2 Aus- und 3-5 Eingänge)&lt;br /&gt;
 		movwf	TRISIO		; schreibe in TRIS Register&lt;br /&gt;
 		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		movlw	7		; schalte Komparator aus&lt;br /&gt;
 		movwf	CMCON		; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 		............&lt;br /&gt;
 		eigener Code&lt;br /&gt;
 		............&lt;br /&gt;
 		return			; springe zurück (zum Haupt)&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm &lt;br /&gt;
                 end			; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Das erste... ==&lt;br /&gt;
&lt;br /&gt;
Hier wird das ganze Prozess der Erstellung eines ASM Programms detailiert beschrieben. Die Idee:&lt;br /&gt;
&lt;br /&gt;
Es gibt 4 LEDs (_L1, _L2, _L3 und _L4), die mit 2 Tastern gesteuert werden sollen. Nach dem Einschalten soll keine LED leuchten. Solange der linke Taster (_T1) gedrückt ist, sollte eine leuchtende LED von links nach rechts &amp;quot;wandern&amp;quot; und von der letzten rechten Position wieder nach ganz linke &amp;quot;springen&amp;quot;. Solange der rechte Taster (_T2) gedrückt ist, sollte eine leuchtende LED von rechts nach links &amp;quot;wandern&amp;quot; und von der letzten linken Position wieder nach ganz rechte &amp;quot;springen&amp;quot;. Solange beide Taster gedrückt sind soll die leuchtende LED von links nach rechts und zurück &amp;quot;wandern&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Dafür nötige Hardware zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
        .-----------------------------------------------.&lt;br /&gt;
        |                                               |&lt;br /&gt;
        |                   PIC12F629                   |&lt;br /&gt;
        |                                               |&lt;br /&gt;
        | GPIO,3  GPIO,4  GPIO,5  GPIO,2  GPIO,1  GPIO,0|&lt;br /&gt;
        '-----------------------------------------------'&lt;br /&gt;
           4|      3|      2|      5|      6|      7|&lt;br /&gt;
            |       |      .-.     .-.     .-.     .-.&lt;br /&gt;
            |       |    R | |   R | |   R | |   R | |&lt;br /&gt;
            |       |   470| |  470| |  470| |  470| |&lt;br /&gt;
            |       |      '-'     '-'     '-'     '-'&lt;br /&gt;
         \  o    \  o       |       |       |       |&lt;br /&gt;
          \       \         V -&amp;gt;    V -&amp;gt;    V -&amp;gt;    V -&amp;gt;&lt;br /&gt;
           \.      \.       -       -       -       -&lt;br /&gt;
        _T1 o   _T2 o   _L1 |   _L2 |   _L3 |   _L4 |&lt;br /&gt;
            |       |       |       |       |       |&lt;br /&gt;
            +-------+-------+---+---+-------+-------+&lt;br /&gt;
                                |&lt;br /&gt;
                               ===&lt;br /&gt;
                               GND&lt;br /&gt;
&lt;br /&gt;
Weil der Pin 4 (GPIO,3) nur einen &amp;quot;open drain&amp;quot; Ausgang hat (kann nur an GND schalten), wird er hier als Eingang benutzt.&lt;br /&gt;
&lt;br /&gt;
Jetzt muss die Idee vom Programmierer in ein PAD verfasst werden, z.B. solcher:&lt;br /&gt;
&lt;br /&gt;
                               Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                 .--------------&amp;gt;V&lt;br /&gt;
                 |     _T1=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   links-&amp;gt;rechts &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 |     _T2=0 gedrückt ? N &amp;gt;----.&lt;br /&gt;
                 |               J             |&lt;br /&gt;
                 |               V             |&lt;br /&gt;
                 |   rechts-&amp;gt;links &amp;quot;wandern&amp;quot;   |&lt;br /&gt;
                 |               V&amp;lt;------------´&lt;br /&gt;
                 `---------------´&lt;br /&gt;
&lt;br /&gt;
danach detailierter:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-------------------------------------------.&lt;br /&gt;
                      _T1=0 gedrückt ? N &amp;gt;---+---&amp;gt;_T2=0 gedrückt ? N &amp;gt;---+---´&lt;br /&gt;
                                J            A              J            A&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                              _L1 an         |            _L4 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L1 aus        |            _L4 aus        |&lt;br /&gt;
                              _L2 an         |            _L3 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L2 aus        |            _L3 aus        |&lt;br /&gt;
                              _L3 an         |            _L2 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L3 aus        |            _L2 aus        |&lt;br /&gt;
                              _L4 an         |            _L1 an         |&lt;br /&gt;
                              Warten         |            Warten         |&lt;br /&gt;
                              _L4 aus        |            _L1 aus        |&lt;br /&gt;
                                V            |              V            |&lt;br /&gt;
                                `------------´              `------------´&lt;br /&gt;
&lt;br /&gt;
Weil das Assemblerprogram (z.B. MPASM) und der Prozessor (CPU) die Befehle nacheinander liest, ist jeder Quelcode einspaltig. Um sich die &amp;quot;Übersetzung&amp;quot; des PADs in den Quelcode zu erleichtern wird er noch z.B. so umgestaltet:&lt;br /&gt;
&lt;br /&gt;
                              Start&lt;br /&gt;
                          Initialisierung&lt;br /&gt;
                                V&amp;lt;-----------------+&amp;lt;----.&lt;br /&gt;
          Haupt       _T1=0 gedrückt ? N &amp;gt;---.     A     | &lt;br /&gt;
                                J            |     |     |&lt;br /&gt;
                                V            |     |     |&lt;br /&gt;
                              _L1 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L1 aus        |     |     |&lt;br /&gt;
                              _L2 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L2 aus        |     |     |&lt;br /&gt;
                              _L3 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L3 aus        |     |     |&lt;br /&gt;
                              _L4 an         |     |     |&lt;br /&gt;
                              Warten         |     |     |&lt;br /&gt;
                              _L4 aus        |     |     |&lt;br /&gt;
                                V&amp;lt;-----------´     |     |&lt;br /&gt;
          T2Test      _T2=0 gedrückt ? N &amp;gt;---------´     |&lt;br /&gt;
                                J                        |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                              _L4 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L4 aus                    |&lt;br /&gt;
                              _L3 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L3 aus                    |&lt;br /&gt;
                              _L2 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L2 aus                    |&lt;br /&gt;
                              _L1 an                     |&lt;br /&gt;
                              Warten                     |&lt;br /&gt;
                              _L1 aus                    |&lt;br /&gt;
                                V                        |&lt;br /&gt;
                                `------------------------´&lt;br /&gt;
&lt;br /&gt;
Alle Pfeilen aus diesem PAD werden als &amp;quot;goto&amp;quot; in den Quelcode eingetragen.&lt;br /&gt;
&lt;br /&gt;
Zuerst wird im MPASM Verzeichnis ein neuer Verzeichniss (z,B. &amp;quot;PIC Programme&amp;quot;) angelegt und in dem Verzeichniss neue Textdatei (z.B. &amp;quot;Erstes.txt&amp;quot;) erstellt. Als nächstes wird die &amp;quot;Vorlage für MPASM&amp;quot; dorthin kopiert.&lt;br /&gt;
&lt;br /&gt;
Danach müssen, die im Programm benutzte Portpins und Register mit &amp;quot;#define&amp;quot; und &amp;quot;equ&amp;quot; definiert werden.&lt;br /&gt;
&lt;br /&gt;
Als Initialisierung wird das UP &amp;quot;Init&amp;quot; aus der Vorlage für MPASM mit geändertem &amp;quot;TRISIO&amp;quot; Wert (0x18) übernommen. Siehe: [[#Vorlage für MPASM|Vorlage für MPASM]]&lt;br /&gt;
 &lt;br /&gt;
Fürs &amp;quot;Warten&amp;quot; wird eine dreifache Warteschleife verwendet. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Die Taster werden mit &amp;quot;btfsc&amp;quot; Befehl geprüft und zum LEDs An- und Ausschalten werden Befehle &amp;quot;bsf&amp;quot; und &amp;quot;bcf&amp;quot; für ensprechenden Portpin von GPIO angewendet. Siehe: [[#Einlesen|Einlesen]] und [[#Ausgeben|Ausgeben]] &lt;br /&gt;
&lt;br /&gt;
Anschlessend wird alles laut PAD in die Vorlage für MPASM eingeschrieben und der Quellcode ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
 	list      P=12F629             ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;          ; entsprechende .inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT  ; Konfiguration &lt;br /&gt;
 #define 	_T1	GPIO,3         ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
 P0 	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1 	equ	0x21&lt;br /&gt;
 P2 	equ	0x22&lt;br /&gt;
  	org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an  (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an  (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an  (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an  (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus (setze den Pin 2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	 GPIO 	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 	 bsf     STATUS,RP0            ; auf Bank1 umschalten&lt;br /&gt;
 	 call 	 0x3FF	    	       ; hole Kalibrationswert (als &amp;quot;retlw&amp;quot; unter Adresse 0x3FF)&lt;br /&gt;
 	 movwf	 OSCCAL                ; und kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
 	 bcf  	 OPTION_REG,7          ; aktiviere pull-ups für die Portpins&lt;br /&gt;
 	 movlw	 0x18                  ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und restlichen als Ausgänge (00011000b)&lt;br /&gt;
 	 movwf	 TRISIO                ; schreibe in TRIS Register&lt;br /&gt;
 	 bcf	 STATUS,RP0            ; auf Bank0 umschalten&lt;br /&gt;
 	 movlw   7                     ; schalte Komparator aus&lt;br /&gt;
 	 movwf   CMCON                 ; und definiere GPIO 0-2 als digitale I/Os&lt;br /&gt;
 	 return                        ; springe zurück (zum Haupt) &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Jetzt wird der Quellcode &amp;quot;Erstes.txt&amp;quot; in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese &amp;quot;*.asm&amp;quot; Datei können wir dem MPASM zum &amp;quot;Übersetzten&amp;quot; geben. Nach der Assemblierung sehen wir 3 Meldungen (Messages) vom MPASM. Diese befinden sich in der vom MPASM erstellter Datei &amp;quot;Erstes.lst&amp;quot; und lauten:&lt;br /&gt;
&lt;br /&gt;
 Message[302]: Register in operand not in bank 0.  Ensure that bank bits are correct.&lt;br /&gt;
&lt;br /&gt;
Diese Meldung kann man übersetzen als:&lt;br /&gt;
&lt;br /&gt;
 Meldung[302]: Register im Befehl nicht in Bank 0. Vergewisse Dich, dass die Bank-Bits korrekt sind.&lt;br /&gt;
&lt;br /&gt;
Wir sind sicher, dass die Register &amp;quot;OSCCAL&amp;quot;, &amp;quot;OPTION_REG&amp;quot; und &amp;quot;TRISIO&amp;quot; in der Bank 1 sich befinden. Wenn man aber nicht sicher ist, soll man im Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich nicht in der Bank 0 befinden und können ignoriert werden.&lt;br /&gt;
&lt;br /&gt;
Am Ende der Datei &amp;quot;Erstes.lst&amp;quot; befinden sich noch einige Informationen über Programmspeicher:&lt;br /&gt;
&lt;br /&gt;
 Program Memory Words Used:    52       ; benutzte Speicherstellen&lt;br /&gt;
 Program Memory Words Free:   972       ; freie Speicherstellen&lt;br /&gt;
&lt;br /&gt;
und die Anzahl den eventuellen Fehlern (Errors), Warnungen (Warnings) und Meldungen (Messages):&lt;br /&gt;
&lt;br /&gt;
 Errors   :     0&lt;br /&gt;
 Warnings :     0 reported,     0 suppressed&lt;br /&gt;
 Messages :     3 reported,     0 suppressed&lt;br /&gt;
&lt;br /&gt;
Insgesamt werden durch MPASM 4 Dateien erstellt: &amp;quot;*.cod&amp;quot;, &amp;quot;*.err&amp;quot;, &amp;quot;*.hex&amp;quot; und &amp;quot;*.lst&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wichtigste davon, falls wegen Fehler keine &amp;quot;*.hex&amp;quot; Datei erstellt wird, ist die &amp;quot;*.err&amp;quot; Datei, wo alles was dem MPASM nicht &amp;quot;passt&amp;quot; aufgelistet ist. In der &amp;quot;*.lst&amp;quot; Datei kann man sich ein Programm mit genauen Adressen für jeden Befehl anschauen.&lt;br /&gt;
&lt;br /&gt;
Bei Erstellung von ASM Programmen, um sich das Kompilieren zu vereinfachen, kann folgende Prozedur verwendet werden:&lt;br /&gt;
&lt;br /&gt;
Zuerst wird in gleichem Verzeichnis, wo sich die Sammlung Unter/Programme befindet, eine Textdatei (z.B. &amp;quot;Test.txt&amp;quot;) erstellt, wo ein einspaltiges PAD mit Pfeilen nach oben und unten geschrieben/skizziert wird. In der Datei wird auch ganz oben ständig aktualisierte Liste aller Register erstellt, die in diesem Unter/Programm verwendet sind.&lt;br /&gt;
&lt;br /&gt;
Wenn das PAD fertig ist, wird diese Datei mit gleichem Namen als &amp;quot;*.asm&amp;quot; Datei (z.B. &amp;quot;Test.asm&amp;quot;)gespeichert und alle PAD &amp;quot;Symbole&amp;quot; mit Befehlen für bestimmten PIC/Assemblerprogramm ersetzt (z.B. für MPASM werden alle Register benannt).&lt;br /&gt;
&lt;br /&gt;
Bei jeder Änderung wird sie gleich in beiden Dateien gemacht, damit sie am Ende wirklich aktuell sind. Letztendlich haben wir dann beide, wenn wir später etwas ändern müssen. Dank dessen braucht man ausser eventuellen Namen der UPs keine Kommentare im Programm schreiben, was seine Erstellung deutlich beschleinigt.&lt;br /&gt;
&lt;br /&gt;
Die während der Assemblierung vom MPASM generierte Datei &amp;quot;Erstes.hex&amp;quot; kann jetzt durch ein Brenner mit geeignetem Programm in den PIC Programmspeicher eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
== Für anderen PIC umschreiben ==&lt;br /&gt;
&lt;br /&gt;
Die wichtigste Vorraussetzung ist, das der andere PIC2, auf dem das vorhandene ASM Programm für PIC1 laufen soll, zumindest für das ASM Programm nötige interne Hardware hat. Die Frequenz des Oszillators sollte gleich sein. Der Code benötigt ausser UP &amp;quot;Init&amp;quot; keine Änderungen.&lt;br /&gt;
&lt;br /&gt;
Wenn der benutzte Port vom PIC2 anderen Namen hat, muss man das im Quellcode umdefinieren, z.B.:&lt;br /&gt;
&lt;br /&gt;
 #define   PORTC      PORTB&lt;br /&gt;
 #define   TRISC      TRISB&lt;br /&gt;
&lt;br /&gt;
Dann wird das Assemblerprogramm, wenn es PORTC findet, immer PORTB nehmen. Das gleiche Betrifft die &amp;quot;__config&amp;quot; Ausdrücke, die entsprechend der &amp;quot;*.ini&amp;quot; Datei für den PIC2, geändert werden müssen. &lt;br /&gt;
&lt;br /&gt;
Das Assemblerprogramm findet sicher alles, was ihm nicht &amp;quot;passt&amp;quot; und bringt Fehlermeldungen, auf die man entsprechend reagieren muss.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel, schreiben wir &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A um.&lt;br /&gt;
&lt;br /&gt;
Zum Ändern sind die ersten 3 Zeilen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=12F629		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P12F629.inc&amp;quot;		  ; entsprechende *.inc Datei für MPASM&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _INTRC_OSC_NOCLKOUT ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Sie werden für den PIC16F84A so aussehen:&lt;br /&gt;
&lt;br /&gt;
 	list      P=16F84A		  ; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;             ; entsprechende *.inc Datei für MPASM &lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC        ; Konfiguration&lt;br /&gt;
&lt;br /&gt;
Dazu muss noch &amp;quot;GPIO&amp;quot; Port umdefiniert werden, da der PIC16F84A solchen nicht hat, z.B. wegen internen pull-ups auf &amp;quot;B&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 #define   GPIO      PORTB&lt;br /&gt;
 #define   TRISIO    TRISB&lt;br /&gt;
&lt;br /&gt;
Die Hardware muss natürlich an entsprechende Pins angeschlossen werden:&lt;br /&gt;
&lt;br /&gt;
_T1 auf 12 (B3), _T2 auf 13 (B4), _L1 auf 14 (B5), _L2 auf 11 (B2), _L3 auf 10 (B1) und _L4 auf 9 (B0) &lt;br /&gt;
&lt;br /&gt;
Jetzt assemblieren wir die Qelldatei und der MPASM bringt in der Datei &amp;quot;Erstes.err&amp;quot; folgende Fehler:&lt;br /&gt;
&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 61 : Symbol not previously defined (OSCCAL)&lt;br /&gt;
 Error[113]   C:\MPASM\PICPROG\PIC16F84\ERSTES.ASM 67 : Symbol not previously defined (CMCON)&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; müssen also noch die Befehle mit &amp;quot;OSCCAL&amp;quot; und &amp;quot;CMCON&amp;quot; Register entfernt werden, da der PIC16F84A sie nicht hat:&lt;br /&gt;
&lt;br /&gt;
           call 	0x3FF 	     	; hole Kalibrationswert&lt;br /&gt;
           movwf	OSCCAL          ; kalibriere internen RC oscillator (4 MHz)&lt;br /&gt;
&lt;br /&gt;
und:&lt;br /&gt;
&lt;br /&gt;
           movlw   7    	        ; schalte Komparator aus&lt;br /&gt;
           movwf   CMCON        	; und mache GPIO 0-2 als digital I/O&lt;br /&gt;
&lt;br /&gt;
Weiter kann schon alles übernommen werden und die Datei &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A ist fertig:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm    &lt;br /&gt;
  	list      P=16F84A	       ; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;          ; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define GPIO    PORTB                  ; Ports umbenennen&lt;br /&gt;
 #define TRISIO  TRISB&lt;br /&gt;
 #define	_T1	GPIO,3		       ; Portpins benennen&lt;br /&gt;
 #define	_T2	GPIO,4&lt;br /&gt;
 #define	_L1	GPIO,5&lt;br /&gt;
 #define	_L2	GPIO,2&lt;br /&gt;
 #define	_L3	GPIO,1&lt;br /&gt;
 #define	_L4	GPIO,0&lt;br /&gt;
 P0	equ	0x20                   ; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
          org 	0x0000                 ; bis da sind MPASM Direktiven&lt;br /&gt;
                                        ; hier fängt das gesamte ASM Programm an&lt;br /&gt;
          call    Init                  ; rufe UP &amp;quot;Init&amp;quot; (Initialisierung) auf&lt;br /&gt;
 Haupt    btfsc   _T1                   ; Taster _T1=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
          goto    T2Test                ; wenn nicht, springe zu &amp;quot;T2Test&amp;quot;&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte ca. 0,4 s (ca. 400 000 Prozessortakten)&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus &lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
 T2Test   btfsc   _T2                   ; Taster _T2=0 gedrückt ?, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
          goto    Haupt                 ; wenn nicht, springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
          bsf     _L4                   ; schalte _L4 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L4                   ; schalte _L4 aus&lt;br /&gt;
          bsf     _L3                   ; schalte _L3 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L3                   ; schalte _L3 aus&lt;br /&gt;
          bsf     _L2                   ; schalte _L2 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L2                   ; schalte _L2 aus&lt;br /&gt;
          bsf     _L1                   ; schalte _L1 an&lt;br /&gt;
          call    Warten                ; warte&lt;br /&gt;
          bcf     _L1                   ; schalte _L1 aus&lt;br /&gt;
          goto    Haupt                 ; springe zu &amp;quot;Haupt&amp;quot;&lt;br /&gt;
 Warten   movlw   2                     ; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
          movwf   P2                    ; ins Register P2&lt;br /&gt;
          clrf    P1                    ; lösche Register P1 (&amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
          clrf    P0                    ; lösche Register P0 (&amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
          decfsz  P0,1                  ; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
          goto    $-1                   ; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
          decfsz  P1,1                  ; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
          goto    $-4                   ; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
          decfsz  P2,1                  ; dekrementiere P2 und überspringe  &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
          goto    $-7                   ; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
          return                        ; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init     clrf 	GPIO	               ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	 bsf    STATUS,RP0  	       ; auf Bank1 umschalten&lt;br /&gt;
  	 bcf  	OPTION_REG,7           ; aktiviere pull-ups&lt;br /&gt;
          movlw	0x18                   ; definiere Portpins GPIO,3 und 4 als Eingänge&lt;br /&gt;
                                        ; und die restlichen als Ausgänge (00011000b) &lt;br /&gt;
  	 movwf	TRISIO	               ; schreibe in TRIS Register&lt;br /&gt;
  	 bcf	STATUS,RP0  	       ; auf Bank0 umschalten&lt;br /&gt;
  	 return	                       ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                        ; aus der du aufgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
Man kann auch die Portpins neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 20.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	_T1	PORTB,5		        ; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 	   org 	0x0000			; bis da sind MPASM Direktiven&lt;br /&gt;
 					; hier fängt das gesamte ASM Programm an&lt;br /&gt;
           call	  Init			; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 Haupt     btfsc   _T1			; Taster T1 gedrückt ist, wenn ja, überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
           goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte ca. 0,4 s (2 000 000 Prozessortakten)&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test    btfsc   _T2			; Taster T2 gedrückt ist, wenn ja, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte _L4 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte _L4 aus&lt;br /&gt;
           bsf     _L3			; schalte _L3 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte _L3 aus&lt;br /&gt;
           bsf     _L2			; schalte _L2 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte _L2 aus&lt;br /&gt;
           bsf     _L1			; schalte _L1 an&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte _L1 aus&lt;br /&gt;
           goto    Haupt		        ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A			; schreibe &amp;quot;0x0A&amp;quot; für ca. 0,4 s&lt;br /&gt;
           movwf   P2			; ins Register P2&lt;br /&gt;
           clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
           clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
           decfsz  P0,1			; dekrementiere P0 und überspringe &amp;quot;goto $-1&amp;quot; bei P0 = 0&lt;br /&gt;
           goto    $-1			; sonst gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
           decfsz  P1,1			; dekrementiere P1 und überspringe &amp;quot;goto $-4&amp;quot; bei P1 = 0 &lt;br /&gt;
           goto    $-4			; sonst gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
           decfsz  P2,1			; dekrementiere P2 und überspringe &amp;quot;goto $-7&amp;quot; bei P2 = 0&lt;br /&gt;
           goto    $-7			; sonst gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
           return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init      clrf    PORTB       		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
  	  bsf     STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
  	  bcf     OPTION_REG,7    	; aktiviere pull-ups&lt;br /&gt;
           movlw   0x30                  ; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
                                         ; und die restlichen als Ausgänge (00011000b)&lt;br /&gt;
  	  movwf	  TRISB   		; schreibe in TRIS Register&lt;br /&gt;
  	  bcf     STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
       	  return	                ; springe zurück (zum Haupt), nach der Zeile&lt;br /&gt;
                                         ; aus der du aufgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
In dem Fall müssen natürlich die Taster und LEDs an für sie definierte Portpins angeschlossen werden.&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschten Programme in ein neues Programm einzubinden ist, alle Programme in das neue Programm zu kopieren. Dafür müssen die ersten 3 Zeilen, die den Prozessor und die Konfiguration des PICs festlegen aus den eigebundenen Programmen entfernt werden.  Danach müssen alle &amp;quot;#define&amp;quot;, &amp;quot;equ&amp;quot; und &amp;quot;org&amp;quot; Direktiven verglichen und wenn nötig geändert werden. Dabei hilft der MPASM mit seinen Fehlermeldungen in der Datei &amp;quot;*.err&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Die zweite Möglichkeit ist, die gewünschten Programme als &amp;quot;*.asm&amp;quot; Dateien mit der Direktive &amp;quot;include *.asm&amp;quot; am Ende des neuen Programms vor der Direktive &amp;quot;end&amp;quot; einzubinden. Die einbindende sowie alle einzubindenden Dateien müssen sich in einem Verzeichniss befinden.&lt;br /&gt;
&lt;br /&gt;
                                           include &amp;quot;1.asm&amp;quot; &lt;br /&gt;
                                           include &amp;quot;2.asm&amp;quot;&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                            .&lt;br /&gt;
                                           include &amp;quot;n.asm&amp;quot; &lt;br /&gt;
                                         end &lt;br /&gt;
&lt;br /&gt;
In dem Fall gelten die gleichen o.g. Regeln wie beim direkten Kopieren. Wenn es in den eingebundenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, werden die weiteren Programme im Programmspeicher ab Ende des ersten Programms nacheinander plaziert.&lt;br /&gt;
&lt;br /&gt;
== Fehlersuche ==&lt;br /&gt;
&lt;br /&gt;
Als erstes wird an den PIC angeschlossene externe Hardware geprüft. Das sollte noch vor dem Einstecken oder Einlöten des PICs gemacht werden, da die gravierende Fehler (z.B. Kurzschlüsse, Umpolung von VCC und GND, usw.) für den PIC schädlich werden können. Für einige Teile der Hardware kann entsprechende Spannung (VCC oder GND) an bestimmten Pin gelegt werden und die richtige Reaktion der Hardware optisch (z.B. für LEDs) oder akustisch (z.B. für Relais) festgestellt werden. Sonst müssen die elektrischen Verbindungen mit einem Messgerät überprüft werden. Danach kann man den PIC einstecken bzw. einlöten.&lt;br /&gt;
&lt;br /&gt;
Die Fehlersuche in der Software fängt mit der ersten und endet mit der letzten Zeile des ASM Programms. Sie läuft die ganze Zeit parallel zum Programmschreiben. Jedes UP sollte vor dem Übertragen ins Programm geprüft und eventuelle Fehler beseitigt werden. Dazu arbeitet man gleichzeitig mit zwei &amp;quot;*.asm&amp;quot; Dateien, einer für die UPs und einer für das gesamte Programm. Es wird empfohlen, nach der &amp;quot;Initialisierung&amp;quot;, als erstes UP, das für Ausgabegerät (z.B. Display) zu erstellen, um das funktionieren des Programms, vom Anfang an beobachten zu können.&lt;br /&gt;
&lt;br /&gt;
Für die Fehlersuche in &amp;quot;hängenden&amp;quot; Programmen ist der [[#PIC RAM Monitor|PIC RAM Monitor]] bzw. [[#PIC Trainer|PIC Trainer]] unersetzlich. Weil sie durch Interrupt das &amp;quot;hängende&amp;quot; Programm unterbrechen und auf dem &amp;quot;PIC Miniterminal&amp;quot; Registerinhalte während der Unterbrechung zeigen, können alle in der endlosen Schleife sich befindliche Register schnell festgestellt werden, da nur dessen Inhalte sich ständig ändern.  &lt;br /&gt;
&lt;br /&gt;
Wenn aus geprüften Unterprogrammen erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD des Hauptprogramms sein.&lt;br /&gt;
&lt;br /&gt;
== Optimierung ==&lt;br /&gt;
Work in Progress...&lt;br /&gt;
Wer sonst noch Beispiele hat, bitte hier vervollständigen...&lt;br /&gt;
BMS ...&lt;br /&gt;
=== Speicherbedarf ===&lt;br /&gt;
==== Programmspeicher ====&lt;br /&gt;
Die ersten Programme für den PIC sind natürlich einfach und kurz. Doch nach und nach werden die Codes länger und unübersichtlicher, das Brennen dauert auch umso länger. Das Programm ist zu umfangreich. Doch wo soll man etwas kürzen?&lt;br /&gt;
&lt;br /&gt;
Es gibt unzählige Möglichkeiten - hier ein paar Beispiele:&lt;br /&gt;
&lt;br /&gt;
===== Unterprogramme =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt wird man im Code immer die selben Abschnitte brauchen, zum Beispiel Warteschleifen oder ADC-Routinen, etc. Wieso sollte man diese also mehrfach (doppelt, dreifach, u.s.w.) schreiben?&lt;br /&gt;
&lt;br /&gt;
Die Lösung: Der Programmteil wird als Unterprogramm benutzt. Man erstellt eine Sprungmarke (ab hier beginnt das Unterprogramm) und endet wieder mit einem &amp;quot;return&amp;quot;- oder &amp;quot;retlw&amp;quot;-Befehl.&lt;br /&gt;
Aufgerufen werden Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; erst ein Codefragment als UP zu definieren wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck nur geeignet, wenn der Prozessor zum letzten Aufruf von &amp;quot;call&amp;quot; zurück springen soll, da die Rücksprungadresse vom letzten &amp;quot;call&amp;quot; auf dem Stapel (stack) abgelegt wurde. Somit kann man mehr als 8 Ebenen von UPs nutzen.&lt;br /&gt;
&lt;br /&gt;
Den Unterprogrammen kann man natürlich auch Werte übergeben. Möchte man z.B. mehrere unterschiedliche Zeiten für Warteschleifen benutzen, so kann man die Werte vor dem Aufruf des UPs in die benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Werte aus dem Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Registern durchzuführen (z.B. löschen) ist die Anwendung von Schleifen geeignet (mit bestimmter Anzahl der Abläufe und indirekter Adressierung). Siehe: [[#Variablen|Variablen]]&lt;br /&gt;
&lt;br /&gt;
===== bsf und bcf =====&lt;br /&gt;
&lt;br /&gt;
Bestimmt gibt es Situationen, in denen der PIC mehrere Bits an einem Port/Register setzen oder löschen muss. Z.B. wenn mehrere LEDs an einem Port ein- oder ausgeschaltet werden sollen.&lt;br /&gt;
Werden mehr als 2 Bits verändert, so kann man hier die &amp;quot;bsf&amp;quot;- und &amp;quot;bcf&amp;quot;-Befehle umgehen und einen kürzeren Code erstellen.&lt;br /&gt;
 &lt;br /&gt;
 bsf PORTB,0 ;An PORTB sind 8 LEDs angeschlossen.&lt;br /&gt;
 bsf PORTB,1 ;Es sollen die ersten 4 LEDs angeschaltet werden,&lt;br /&gt;
 bsf PORTB,2 ;die anderen sollen ausgeschaltet werden.&lt;br /&gt;
 bsf PORTB,3 ;links steht es mit bcf/bsf&lt;br /&gt;
 bcf PORTB,4 ;ziemlich lang&lt;br /&gt;
 bcf PORTB,5&lt;br /&gt;
 bcf PORTB,6&lt;br /&gt;
 bcf PORTB,7&lt;br /&gt;
 &lt;br /&gt;
 movlw b'00001111' ;Das geht auch kürzer und übersichtlicher:&lt;br /&gt;
 movwf PORTB&lt;br /&gt;
&lt;br /&gt;
Man sieht - der Codeabschnitt umfasst nur noch 2 Zeilen anstatt 8. Somit braucht es weniger Speicher und wird von PIC schneller verarbeitet. Allerdings muss man aufpassen, da durch diese Routine der Inhalt des W-Registers und der Inhalt des &amp;lt;i&amp;gt;gesamten&amp;lt;/i&amp;gt; Zielregisters verändert wird. Sollen die anderen Bits unangetastet bleiben, muss man es entweder bei den &amp;quot;bcf&amp;quot;/&amp;quot;bsf&amp;quot;-Befehlen belassen oder logische Funktionen (and bzw. or) durchführen.&lt;br /&gt;
&lt;br /&gt;
===== Bit kopieren =====&lt;br /&gt;
&lt;br /&gt;
 ;An den PIC ist ein Taster(RB0) und eine LED(RB1) angeschlossen.&lt;br /&gt;
 ;Taster: High=gedrückt  Low=nicht gedrückt&lt;br /&gt;
 ;LED:    High=Ein       Low=Aus&lt;br /&gt;
 ;Wenn der Taster gedrückt ist, soll die LED leuchten&lt;br /&gt;
 ;wenn er nicht gedrückt ist, soll die LED nicht leuchten.&lt;br /&gt;
 ;1.Vorschlag:&lt;br /&gt;
       btfss PORTB,0 ;ist der taster gedrückt?&lt;br /&gt;
       goto no       ;nein&lt;br /&gt;
       bsf PORTB,1   ;ja - LED ein&lt;br /&gt;
       goto endif    ;fertig abgefragt - unten weitermachen...&lt;br /&gt;
 no    bcf PORTB,1   ;LED aus&lt;br /&gt;
 endif&lt;br /&gt;
&lt;br /&gt;
Der oben aufgeführte Code hat viele Nachteile: er ist relativ lang, braucht zwei Gotos und entspr. Sprungmarken. Ok, das ist vielleicht Erbsenzählerei, aber aus diesen 5 Zeilen kann man 3 machen.&lt;br /&gt;
&lt;br /&gt;
 bcf PORTB,1   ;Das Bit wird erst gelöscht&lt;br /&gt;
 btfsc PORTB,0 ;Taster gedrückt?&lt;br /&gt;
 bsf PORTB,1   ;JA-LED an&lt;br /&gt;
&lt;br /&gt;
Man geht davon aus, dass der Taster nicht gedrückt ist. Somit wird die LED erst einmal ausgeschaltet. Ist der Taster aber doch gedrückt, dann wird die LED angeschaltet.&lt;br /&gt;
&lt;br /&gt;
Achtung möglicher Nebeneffekt: Wird dies in einer Schleife sehr schnell und oft ausgeführt, kann die LED flimmern oder nicht in ihrer vollen Helligkeit leuchten. Das passiert, weil ja angenommen wird, dass der Taster nicht gedrückt wird und die LED somit aus sein muss. Dann wird sie aber bei Tastendruck eingeschaltet. Somit entsteht ein schnelles ein-/ausschalten (PWM) und die LED leuchtet nicht mehr so hell.&lt;br /&gt;
Meist ist das aber nicht tragisch oder wird nicht unbedingt in einer Schleife sehr schnell abgefragt. Siehe hierzu: [[#Einlesen|Einlesen]]&lt;br /&gt;
&lt;br /&gt;
==== RAM ====&lt;br /&gt;
&lt;br /&gt;
Um Anzahl benötigten Register zu sparen werden vorläufige Register (temporary) definiert, die von mehreren UPs benutzt werden. Als Beispiel, das Register &amp;quot;Tmp&amp;quot; in [[#Matrix Display|Matrix Display]] oder &amp;quot;ATmp&amp;quot; in [[#Hex Dec Wandlung|Hex Dec Wandlung]]. Die Benutzung muss aber sehr genau nach PAD zugeteilt werden. Bei gleichzeitiger Benutzung des gleichen Registers durch mehrere UPS werden falsche Daten verarbeitet und im schlimmsten Fall können endlose Schleifen entstehen, die in Folge haben, dass das Programm nicht weiter ausgeführt wird (&amp;quot;hängt&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Viele im ASM Programm ungebrauchte SFRs können als &amp;quot;normale&amp;quot; Register (GPR) verwendet werden. Wenn zum Beispiel Timer1 nicht benutzt wird, können seine Register TMR1H und TMR1L für Speicherung von Daten benutzt werden. Es könnte aber gefährlich werden, wenn mehrere Programme gebindet sind. Deswegen muss es immer am Ende, beim volständigen Programm, geprüft werden, welche SFRs tatsächlich benutzt werden dürfen. &lt;br /&gt;
 &lt;br /&gt;
Für Konstanten (z.B. pi, ln2, Meldungen, usw.), die sich im Laufe des Programms nicht ändern, kann EEPROM (mit MPASM Direktive &amp;quot;de&amp;quot;) oder Programmspeicher (mit MPASM Direktive &amp;quot;dt&amp;quot;) als Ablage benutzt werden. Siehe auch: [[#EEPROM|EEPROM]] und [[#Tabellen|Tabellen]]&lt;br /&gt;
&lt;br /&gt;
=== Ausführungszeit ===&lt;br /&gt;
&lt;br /&gt;
Alles was schnellmöglichst ablaufen soll, widersetzt sich der Optimierung des Programmspeichers.&lt;br /&gt;
&lt;br /&gt;
Es können keine Schleifen und keine indirekte Adressierung benutzt werden, alles muss direkt programmiert werden. &lt;br /&gt;
&lt;br /&gt;
Als Beispiel zur Verdeutlichung: Es sollen 16 Werte vom PORTA ins RAM ab Adresse 0x20 eingelesen werden.&lt;br /&gt;
&lt;br /&gt;
Als Schleife mit indirekter Adressierung:&lt;br /&gt;
&lt;br /&gt;
 					................&lt;br /&gt;
 					movlw	0x10            ;Anzahl Durchläufe&lt;br /&gt;
 					movwf	Temp		;in den Schleifenzähler&lt;br /&gt;
 					movlw	0x20		;erste Adresse&lt;br /&gt;
 					movwf	FSR             ;ins FSR Register&lt;br /&gt;
 			Einlesen	movf	PORTA,0         ;PortA ins W-Register&lt;br /&gt;
 					movwf	INDF            ;und ins aktuellen RAM Register&lt;br /&gt;
 					incf	FSR,1           ;nächste Adresse&lt;br /&gt;
 					decfsz	Temp,1          ;Temp = 0 ?&lt;br /&gt;
 					goto	Einlesen        ;nein, zum Einlesen&lt;br /&gt;
 					................        ;ja, weiter &lt;br /&gt;
 					Gesamtdauer: 100 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 6 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 9 Speicherstellen &lt;br /&gt;
Direkt:&lt;br /&gt;
&lt;br /&gt;
 					...............&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x20&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x21&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x22&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x23&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x24&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x25&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x26&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x27&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x28&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x29&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2A&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2B&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2C&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2D&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2E&lt;br /&gt;
 					movf	PORTA,0&lt;br /&gt;
 					movwf	0x2F&lt;br /&gt;
 					...............&lt;br /&gt;
 					Gesamtdauer: 32 Takten&lt;br /&gt;
 					Pause zwischen Einlesungen: 2 Takten&lt;br /&gt;
                                         Programmspeicher Bedarf: 32 Speicherstellen&lt;br /&gt;
&lt;br /&gt;
Anstatt Warteschleifen (z.B. für Tastenentprellung) sollten Programmfragmente mit entsprechender Ausführungszeit benutzt werden (z.B. Ausgabe auf einem Display). Die nötige Zeit lässt sich aus mehreren UPs zusammensetzen.&lt;br /&gt;
&lt;br /&gt;
Es sollte kein Prozessortakt ungenutzt bleiben.&lt;br /&gt;
&lt;br /&gt;
Man kann auch eine Bearbeitung eines UPs um 4 Takte beschleunigen (&amp;quot;call&amp;quot; + &amp;quot;return&amp;quot;), indem man bei dem letzten Aufruf eines UPs (direkt vorm &amp;quot;return&amp;quot;) anstatt &amp;quot;call UP&amp;quot;, &amp;quot;goto UP&amp;quot; anwendet, da das UP sowieso mit &amp;quot;return&amp;quot; bzw. &amp;quot;retlw&amp;quot; endet.&lt;br /&gt;
&lt;br /&gt;
Ursprünglich:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	Cmd &amp;lt;--&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Optimiert:&lt;br /&gt;
&lt;br /&gt;
 		movlw	0x28&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		goto	Cmd &amp;lt;--&lt;br /&gt;
&lt;br /&gt;
Nebenbei sparrt man sich eine Zeile im Quellcode und eine Spaicherstelle im Programmspeicher.&lt;br /&gt;
&lt;br /&gt;
= Basic-Line (PIC12...) &amp;amp; Mid-Range (PIC16...)=&lt;br /&gt;
&lt;br /&gt;
Zu Basic-Line gehören alle PIC12... mit 12-bit und zu Mid-Range alle PIC16... mit 14-bit langen Befehlen. Weil beide Familien gleichen Befehlsatz haben, werden sie hier gemeinsam behandelt. Sie haben insgesamt 35 Befehle.&lt;br /&gt;
&lt;br /&gt;
Alle Befehle aus der Tabelle, ausser mit &amp;quot;*&amp;quot; gekenzeichneten, gehören zum Befehlsatz den High-End PIC18... dazu.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht Assembler Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDLW||Add literal and W &lt;br /&gt;
|-&lt;br /&gt;
|ADDWF||Add W and f &lt;br /&gt;
|-&lt;br /&gt;
|ANDLW||AND literal with W &lt;br /&gt;
|-&lt;br /&gt;
|ANDWF||AND W with f&lt;br /&gt;
|-&lt;br /&gt;
|BCF||Bit Clear f &lt;br /&gt;
|-&lt;br /&gt;
|BSF||Bit Set f &lt;br /&gt;
|-&lt;br /&gt;
|BTFSC||Bit Test f, Skip if Clear &lt;br /&gt;
|-&lt;br /&gt;
|BTFSS||Bit Test f, Skip if Set &lt;br /&gt;
|-&lt;br /&gt;
|CALL||Call subroutine &lt;br /&gt;
|-&lt;br /&gt;
|CLRF||Clear f&lt;br /&gt;
|-&lt;br /&gt;
|*CLRW||Clear W&lt;br /&gt;
|-&lt;br /&gt;
|CLRWDT||Clear Watchdog Timer &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|COMF||Complement f&lt;br /&gt;
|-&lt;br /&gt;
|DECF||Decrement f&lt;br /&gt;
|-&lt;br /&gt;
|DECFSZ||Decrement f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|GOTO||Go to address or label&lt;br /&gt;
|-&lt;br /&gt;
|INCF||Increment f&lt;br /&gt;
|-&lt;br /&gt;
|INCFSZ||Increment f, Skip if 0&lt;br /&gt;
|-&lt;br /&gt;
|IORLW||Inclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|IORWF||Inclusive OR W with f&lt;br /&gt;
|-&lt;br /&gt;
|MOVF||Move f&lt;br /&gt;
|-&lt;br /&gt;
|MOVLW||Move literal to W &lt;br /&gt;
|-&lt;br /&gt;
|MOVWF||Move W to f&lt;br /&gt;
|-&lt;br /&gt;
|NOP||No Operation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|RETFIE||Return from interrupt &lt;br /&gt;
|-&lt;br /&gt;
|RETLW||Return with literal in W &lt;br /&gt;
|-&lt;br /&gt;
|RETURN||Return from Subroutine &lt;br /&gt;
|-&lt;br /&gt;
|*RLF||Rotate Left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|*RRF||Rotate Right f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|SLEEP||Go into standby mode &lt;br /&gt;
|-&lt;br /&gt;
|SUBLW||Subtract W from literal &lt;br /&gt;
|-&lt;br /&gt;
|SUBWF||Subtract W from f&lt;br /&gt;
|-&lt;br /&gt;
|SWAPF||Swap nibbles in f&lt;br /&gt;
|-&lt;br /&gt;
|XORLW||Exclusive OR literal with W &lt;br /&gt;
|-&lt;br /&gt;
|XORWF||Exclusive OR W with f&lt;br /&gt;
|}&lt;br /&gt;
[[:bild:pic_asm_short.jpg|Kurzübersicht zum Ausdrucken]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Ausführliche Beschreibung zu den Befehlen==&lt;br /&gt;
&lt;br /&gt;
Fast alle Befehle werden in einem Takt = 4 Oszillatortakten ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Aussnahmen:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;goto&amp;quot;, &amp;quot;call&amp;quot;, &amp;quot;return&amp;quot; und &amp;quot;retfie&amp;quot; benötigen wegen Zugriff auf den Programmzähler (PC) immer 2 Takten.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;btfsc&amp;quot;, &amp;quot;btfss&amp;quot;, &amp;quot;decfsz&amp;quot; und &amp;quot;incfsz&amp;quot; brauchen 1 Takt wenn der nächste Befehl ausgeführt wird bzw. 2 Takten wenn er überspringen wird, weil es immer anstatt des überspringenden Befehls ein &amp;quot;nop&amp;quot; ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
Eine ausgegliederte Beschreibung der Befehle findet sich unter [[PIC Assemblerbefehle]]&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD Literal and W - Addiere Zahl (k) und W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+k&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ADDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;ADD W and F - Addiere W und f &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ and\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- and&lt;br /&gt;
 10001000        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Löschen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gelöscht werden sollen, werden in W-Register mit 0 und die unbeeinflußte mit 1 angegeben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; ANDWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;AND W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ and\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit ANDLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BCF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Clear F  - Bit b im R wird gelöscht&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BCF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gelöscht. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    movlw b'11111111'     ;es wird b'11111111' in das W-Register geschrieben&lt;br /&gt;
    BCF W,2               ;es wird bit 2 im W-Register gelöscht.&lt;br /&gt;
                          ;das Ergebnis ist: b'11111011'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BSF R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Set F  - Bit b im R wird gesetzt&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BSF&amp;lt;/tt&amp;gt; wird das Bit '''b''' im Register '''R''' gesetzt. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
    clrw                   ;es wird b'00000000' in das W-Register geschrieben&lt;br /&gt;
    BSF W,2                ;es wird bit 2 im W-Register gesetzt.&lt;br /&gt;
                           ;das Ergebnis ist: b'00000100'&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSC R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Clear  - Wenn das Bit b im Register R 0 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSC&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 0 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSC W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 0 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt.&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTFSS R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Bit Test F, Skip if Set  - Wenn das Bit b im Register R 1 ist, überspringe den nächsten Befehl&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem Befehl &amp;lt;tt&amp;gt;BTFSS&amp;lt;/tt&amp;gt; kann eine Verzweigung im Programmablauf bewirkt werden. Wenn das Bit '''b''' im Register '''R''' 1 ist, wird der nächste Befehl übersprungen. Ein Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw b'00000001'     ;es wird die Zahl 1 in das W-Register kopiert.&lt;br /&gt;
     BTFSS W,0             ;es wird bit 0 geprüft.&lt;br /&gt;
                           ;wenn es 1 ist, wird der nächste Befehl übersprungen&lt;br /&gt;
     goto  IST_NULL        ;springt zur Marke &amp;quot;IST_NULL&amp;quot;&lt;br /&gt;
     goto  IST_EINS        ;springt zur Marke &amp;quot;IST_EINS&amp;quot; &amp;lt;- in diesem Fall wird dieser&lt;br /&gt;
                           ;Sprungbefehl ausgeführt, da der Befehl&lt;br /&gt;
                           ;darüber übersprungen wurde.&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CALL Subroutine  - Rufe Unterprogramm auf&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl wird ein Unterprogramm aufgerufen. Mit &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt;-Befehl wird das Unterprogramm beendet und man kehrt zum Befehl nach dem &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt;-Befehl zurück. Das Unterprogramm wird so definiert, dass im Quellcode der Name des Unterprogramms nicht eingerückt steht. Ein Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     movlw d'13'           ;in das W-Register wird 13d geladen&lt;br /&gt;
     CALL  UP1             ;es wird das Unterprogramm &amp;quot;UP1&amp;quot; aufgerufen&lt;br /&gt;
     movwf ergebnis        ;das W-Register wird in das Register &amp;quot;ergebnis&amp;quot; kopiert.&lt;br /&gt;
                           ;im Register &amp;quot;ergebnis&amp;quot; steht nun 23d&lt;br /&gt;
       &lt;br /&gt;
 UP1 addlw d'10'           ;es wird 10d zum W-Register addiert&lt;br /&gt;
     return                ;kehre zurück zum Aufrufer&lt;br /&gt;
&amp;lt;/dl&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR F- Schreibe 0 in das Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register '''R''' wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR W - Schreibe 0 in W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CLRWDT&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;CLeaR WatchDog Timer - Setzt den Watchdog-Timer zurück&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der WDT (Watchdog-Timer) zurückgesetzt und der Zähler des WDT  auf 0 gesetzt, zusätzlich werden die STATUS-bits TO und PD gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;COMF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;COMplement F - negiere alle bits im Register R&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Von der Binärzahl im Register '''R''' werden alle 0 mit 1 und alle 1 mit 0 ersetzt. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Ein kleines Beispiel: aus &amp;lt;tt&amp;gt;AAh&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;10101010b&amp;lt;/tt&amp;gt;) wird &amp;lt;tt&amp;gt;55h&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;01010101b&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F - Subtrahiert 1 vom Regiser f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DECFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;DECrement F, Skip if Zero - Subtrahiert 1 vom Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;GOTO&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;GO TO address - Gehe zu Adresse/Sprungmarke&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Nach dem GOTO Befehl wird das Programm ab der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarke definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt im Quellcode stehen.&lt;br /&gt;
&lt;br /&gt;
:Um die Anzahl den Sprungmarken im Programm zu verringern, kann auch indirekte Adressierung von Sprungzielen mit &amp;quot;GOTO $+n&amp;quot; bzw. &amp;quot;GOTO $-n&amp;quot; benutzt werden. Das Symbol &amp;quot;$&amp;quot; bedeutet immer die aktuelle Adresse vom Programmzähler (PC). Das Assemblerprogramm, das sowieso jede Sprungmarke in entsprechende absolute Adresse wandelt, erzeugt in diesem Fall die Zieladresse als &amp;quot;PC+n&amp;quot; bzw. &amp;quot;PC-n&amp;quot;, wobei &amp;quot;n&amp;quot; immer als hexadezimale Zahl genommen wird.&lt;br /&gt;
&lt;br /&gt;
:Der Befehl &amp;quot;goto $+1&amp;quot; verbraucht nur Zeit von zwei &amp;quot;nop&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
:Beispiele dazu sind in [[#Pause|Pause]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F - Addiere 1 zum Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Weil es keine &amp;quot;echte&amp;quot; Addition ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INCFSZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;INCrement F, Skip if Zero - Addiere 1 zum Regiser f, überspringe wenn 0&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SZ steht für ''skip if zero'', d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen. Dieser Befehl wird für Schleifen mit bestimmter Anzahl der Durchläufe benutzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; IORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ or\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- or&lt;br /&gt;
 11101110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird zum Setzen bestimmten Bits im Register benutzt, ohne restlichen Bits zu beeinflussen. Die bits, die gesetzt werden sollen, werden in W-Register mit 1 und die unbeeinflußte mit 0 angegeben.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt; IORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Inclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ or\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche mit IORLW.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe F - Bewege f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R wird in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder wieder in R kopiert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Register gesetzt wird, falls R Null ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe Literal to W - Bewege Zahl (k) in W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der festgelegte Wert k wird in das W-Register geladen.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW	0xA3         ;ins W-Register wird eine Zahl A3h geladen&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Dieser Befehl wird auch bei indirekter Adressierung zum laden der absoluter Adresse ins &amp;quot;FSR&amp;quot; Register benutzt. Beispiel:&lt;br /&gt;
:Der Register &amp;quot;A3&amp;quot; wurde mit &amp;quot;A3   equ   23&amp;quot; definiert.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 MOVLW   A3          ;ins W-Register wird die absolute Adresse 23h vom &amp;quot;A3&amp;quot; geladen&lt;br /&gt;
 movwf   FSR         ;diese Adresse wird jetzt ins Register &amp;quot;FSR&amp;quot; kopiert &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;MOVWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;MOVe W to F- Bewege W-Register in das Register F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das W-Register wird in das Register '''R''' kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NOP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;No OPeration - Kein Befehl zum Ausführen (warte)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. &amp;lt;math&amp;gt;t=\frac{4}{f}&amp;lt;/math&amp;gt;,wobei &amp;lt;math&amp;gt;f&amp;lt;/math&amp;gt; für die Frequenz des Oszillators steht. Siehe hierzu: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETFIE&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn From Interrupt Enable - Kehre zurück aus der Unterbrechung, erlaube Unterbrechungen&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Mit diesem Befehl wird die Interrupt Service Routine (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch [[#Interrupt | Interrupt]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETurn with Literal in W - Kehre zurück mit Zahl k im W-Register&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETLW&amp;lt;/tt&amp;gt; zurück in die nächste Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dies wird benutzt um zu erkennen aus welchem UP das verzweigte Programm zurückkommt. Dieser Befehl wird aber vor allem für s.g. Wertetabellen (eng: lookup tables) verwendet.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RETURN&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;RETURN from Subroutine - Kehre zurück zum Aufrufer&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Wurde ein Programmteil mit dem Befehl &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; aufgerufen, dann springt man mit dem Befehl &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; zurück zu der nächsten Zeile nach der Zeile aus der das &amp;lt;tt&amp;gt;CALL&amp;lt;/tt&amp;gt; Befehl ausgeführt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Left F through carry - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Rotate Right F through carry - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SLEEP &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus (Schlaf)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBLW k &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from Literal - Ziehe W von Zahl (k)  ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;k-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; SUBWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SUBtract W from F - Ziehe W von f ab&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;R-W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    d'20'       ;schreibe 20 in das W-Register&lt;br /&gt;
 movwf    Register1   ;bewegt das W-Register in das Register1&lt;br /&gt;
 movlw    d'10'       ;schreibt 10 in das W-Register&lt;br /&gt;
 SUBWF    Register1,F ;schreibt Register1(20)-W(10) in Register1&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SWAPF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;SWAP nibbles in F  - Vertausche die Halbbytes (Nibbles)&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden die Nibbles, also die höheren 4 bits (bit7-bit4) mit den niedrigeren 4 bits (bit3-bit0) eines Registers vertauscht und entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).&lt;br /&gt;
:Beispiel:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 movlw    b'00001111' ;schreibe b'00001111' in das W-Register&lt;br /&gt;
 movwf    Register1   ;kopiert das W-Register in das Register1&lt;br /&gt;
 SWAPF    Register1,W ;vertauscht die ersten 4 bit mit den letzen&lt;br /&gt;
                      ;4 bit in Register 1 und schreibt es in das W-Register&lt;br /&gt;
                      ;im W-Register steht nun b'11110000'&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Der Befehl wird immer zum Sichern und Wiederherstellen des STATUS-Registers am Anfang und Ende einer  ISR (interrupt service routine) verwendet, da er das STATUS-Register nicht beeinflußt (verändert keine STATUS bits).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR Literal with W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;k\ xor\ W&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist.&lt;br /&gt;
&lt;br /&gt;
:Zur Verdeutlichung der Operation:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 11001010        ;k&lt;br /&gt;
 10101100        ;W-Register&lt;br /&gt;
 -------- xor&lt;br /&gt;
 01100110        ;W-Register&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:Dieser Befehl wird vor allem zum Vergleichen eines Registers mit ins W-Register geladenem Wert benutzt. Wenn die Werte in beiden Register gleich sind, wird ein Z bit im STATUS-Register gesetzt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt; XORWF R,d &amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;EXclusive OR W with F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird bitweise die logische Funktion &amp;lt;math&amp;gt;W\ xor\ R&amp;lt;/math&amp;gt; ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Vergleiche XORLW. Dieser Befehl setzt das Z bit des STATUS-Registers, falls W=k und das Ergebnis 0 ist. Er wird zum Vergleichen zwei Register benutzt, wobei ein Register vorher ins W-Register geladen wird..&lt;br /&gt;
&lt;br /&gt;
==Besondere, oft gebrauchte Register==&lt;br /&gt;
&lt;br /&gt;
=== STATUS === &lt;br /&gt;
Der Statusregister beinhaltet den Status der Recheneinheit ALU (Arithmetic-Logic Unit), Resetinformationen und die beiden Bits zur Wahl der Speicherbank&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''STATUS''' (ADDRESSE 03h, 83h, 103h, 183h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R-1&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''IRP'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RP0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TO'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PD'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Z'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''DC'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''C'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''IRP''': Register Bank Select Bit (für indirekte Adressierung)&lt;br /&gt;
:: 1 = Bank 2, 3 (100h-1FFh)&lt;br /&gt;
:: 0 = Bank 0, 1 (00h-FFh)&lt;br /&gt;
*Bit 6-5 '''RP&amp;lt;1:0&amp;gt;''': Register Bank Select Bits (für direkte Adressierung)&lt;br /&gt;
:: 11 = Bank 3 (180h-1FFh)&lt;br /&gt;
:: 10 = Bank 2 (100h-17Fh)&lt;br /&gt;
:: 01 = Bank 1 (80h-FFh)&lt;br /&gt;
:: 00 = Bank 0 (00h-7Fh) &lt;br /&gt;
*Bit 4 '''TO''': Time-out Bit&lt;br /&gt;
:: 1 = Nach Power-up, CLRWDT Befehl oder SLEEP Befehl&lt;br /&gt;
:: 0 = A Watchdogtimer time-out ist eingetreten&lt;br /&gt;
*Bit 3 '''PD''': Power-Down Bit&lt;br /&gt;
:: 1 = Nach Power-up oder durch den CLRWDT&lt;br /&gt;
:: 0 = Nach einem SLEEP befehl&lt;br /&gt;
*Bit 2 '''Z''': Zero bit&lt;br /&gt;
:: 1 = Das Ergebnis einer arithmetischen oder logischen Operation ist 0&lt;br /&gt;
:: 0 = Das Ergebnis einer arithmetischen oder logischen Operation ist NICHT 0&lt;br /&gt;
*Bit 1 '''DC''': Digit carry/borrow bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des 4.Niedrigsten Bits (Low Nibble) eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des 4.Niedrigsten Bits eines Rechenergebnisses existiert&lt;br /&gt;
*Bit 0 '''C''': Carry/borrow Bit (ADDWF, ADDLW, SUBLW und SUBWF Befehle)&lt;br /&gt;
:: 1 = Ein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
:: 0 = Kein Carry-out des MSB eines Rechenergebnisses existiert&lt;br /&gt;
&lt;br /&gt;
Das &amp;quot;Carry/Borrow Bit&amp;quot; (to carry = etwas übertragen, to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250d+10d ergibt zum Beispiel 4, und setzt dabei das &amp;quot;Carry/Borrow Bit&amp;quot; auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255d herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das &amp;quot;Carry/Borrow Bit&amp;quot; umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55d-6=49d setzt &amp;quot;Carry/Borrow Bit&amp;quot; auf 1 aber 10d-25d=241d löscht das &amp;quot;Carry/Borrow Bit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Registers====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Subtraktionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| negativ&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
||&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Auswirkungen auf das STATUS-Register bei Additionen&lt;br /&gt;
|-&lt;br /&gt;
| Ergebnis&lt;br /&gt;
|| STATUS,C&lt;br /&gt;
|| STATUS,Z&lt;br /&gt;
|-&lt;br /&gt;
| positiv&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Überlauf&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Null&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== OPTION_REG ===&lt;br /&gt;
&lt;br /&gt;
Durch OPTION_REG werden PORTB pull-ups, aktive Flanke des externen Interrupts, der Prescaler und der Timer0 konfiguriert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''OPTION_REG''' (ADDRESSE 81h, 181h)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''/RBPU'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INTEDG'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0CS'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''T0SE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PSA'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PS0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''/RBPU''': PORTB Pull-up Enable bit (&amp;quot;/&amp;quot; bedeutet Negation)&lt;br /&gt;
::1 = Pull-ups sind deaktiviert &lt;br /&gt;
::0 = Pull-ups sind aktiviert für die Pins, die im Register TRISB als Eingänge definiert sind&lt;br /&gt;
*Bit 6 '''INTEDG''': Interrupt Edge Select bit&lt;br /&gt;
::1 = Interrupt auf steigende Flanke am RB0/INT pin&lt;br /&gt;
::0 = Interrupt auf fallende Flanke am RB0/INT pin&lt;br /&gt;
*Bit 5 '''T0CS''': Timer0 Clock Source Select bit&lt;br /&gt;
::1 = Wechsel am RA4/T0CKI pin&lt;br /&gt;
::0 = Internes Taktsignal (Fosc/4), wo Fosc ist gleich der Frequenz des Oszillators (z.B. Quarz)&lt;br /&gt;
*Bit 4 '''T0SE''': TMR0 Source Edge Select bit&lt;br /&gt;
::1 = Inkrementiere bei fallender Flanke am RA4/T0CKI pin&lt;br /&gt;
::0 = Inkrementiere bei steigender Flanke am RA4/T0CKI pin&lt;br /&gt;
*Bit 3 '''PSA''': Prescaler Assignment bit&lt;br /&gt;
::1 = Prescaler ist dem WDT zugewiesen&lt;br /&gt;
::0 = Prescaler ist dem Timer0 zugewiesen&lt;br /&gt;
*Bit 2-0 '''PS2:PS0''': Prescaler Rate Select bit&lt;br /&gt;
&lt;br /&gt;
Je nach Zuweisung des Prescalers (durch PSA bit) wird die interne Taktfrequenz des Prozessors (Fosc/4) wie folgt geteilt:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
| PS2:PS0&lt;br /&gt;
|| TMR0&lt;br /&gt;
|| WDT&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|000&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:1&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|001&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:2&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|010&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:4&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|011&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:8&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|100&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:16&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|101&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:32&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|110&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:64&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|111&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:256&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1:128&lt;br /&gt;
|}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== PORTx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''PORTx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''Rx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;PORTB&amp;quot; oder &amp;quot;RA1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Diese Special Funktion Register liegen ALLE in Bank0 und Bank2 (Falls vorhanden).&lt;br /&gt;
&lt;br /&gt;
Jedes Bit eines PORT-Registers steht für einen Pin (Ein/Ausgang) des jeweiligen Ports. Je nachdem Ob ein Pin als Ausgang oder als Eingang definiert ist, kann man dort entweder den Wert schreiben oder auslesen. Es hat nicht Jeder PIC gleich viele Ports und es sind auch nicht immer 8 Pins pro Port, es können auch weniger sein. Alle PICs der Midrange-Serie besitzen nur bidirektionale Ports, d.h. sie können sowohl Eingang als auch Ausgang sein. Bei Port B kann man bei allen Pins einen internen PULL-UP Widerstand mit dem Bit OPTION_REG&amp;lt;RBPU&amp;gt; hinzuschalten (Standardmäßig auf nicht aktiviert, Bit muss gelöscht werden um die Funktion zu aktivieren). Weiters ist zu beachten, dass einzelne Pins nach dem Reset mit anderen Funktionen belegt sein können. Das gilt im Speziellen für PORTA, wo sich die Komperatoren, AD's (falls vorhanden) und die Oszillatoreingänge befinden. Siehe [[PIC Assembler#I/O Ports|I/O Ports]]. Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der PORT-Register GPIO. &lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|+ Beispiel PICs und ihre Ports  (Zahlen in der Klammer sind die Anzahl der Pins des Ports)&lt;br /&gt;
|&lt;br /&gt;
|'''PIC16F628A'''&lt;br /&gt;
|'''PIC16F876'''&lt;br /&gt;
|'''PIC16F877'''&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTA'''&lt;br /&gt;
|Ja&lt;br /&gt;
|Ja(5)&lt;br /&gt;
|Ja(6)&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTB'''&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTC'''&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTD'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja&lt;br /&gt;
|-&lt;br /&gt;
|'''PORTE'''&lt;br /&gt;
|/&lt;br /&gt;
|/&lt;br /&gt;
|ja (3)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TRISx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''TRISx'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx7'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx6'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx5'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx4'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx3'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx2'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx1'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TRISx0'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
!Das &amp;quot;x&amp;quot; steht in allen Fällen für den Buchstaben des Ports!&lt;br /&gt;
BSP: &amp;quot;TRISB&amp;quot; oder &amp;quot;TRISA&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Bei den &amp;quot;kleinsten&amp;quot; PICs der 12F Serie die nur einen I/O Port (6 Pins) haben, heisst der TRIS-Register TRISIO.&lt;br /&gt;
&lt;br /&gt;
Die TRIS-Bytes dienen dazu, einzelne I/O Pins als Eingang oder Ausgang zu definieren. Sie liegen immer genau eine Bank über den jeweiligen PORT-Bytes, d.h. sie liegen alle in Bank1 und Bank3 (falls vorhanden.) Besonders zu beachten ist, dass manche Eingebaute Features wie die Serielle Schnittstelle, I2C, SPI usw nicht funktionieren, wenn die Jeweiligen Sende und Empfangspins nicht manuell umgestellt werden, ja es ''muss'' sogar manchmal umgestellt werden (bei I2C z.B.) Egal ist dies jedoch für Komperatoren und AD-Wandler.&lt;br /&gt;
&lt;br /&gt;
Merke:&lt;br /&gt;
* Eine 1 (als &amp;quot;I&amp;quot; für &amp;quot;Input&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Eingang.&lt;br /&gt;
* Eine 0 (als &amp;quot;O&amp;quot; für &amp;quot;Output&amp;quot; zu lesen) eines TRISxx-Bits definiert den zugehörigen PIN am PIC als Ausgang.&lt;br /&gt;
&lt;br /&gt;
Siehe [[PIC Assembler#I/O Ports|I/O Ports]].&lt;br /&gt;
&lt;br /&gt;
=== INTCON === &lt;br /&gt;
&lt;br /&gt;
&amp;lt;table style=&amp;quot;text-align: center;&amp;quot; cellspacing=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;8&amp;quot; style&amp;gt;'''INTCON''' (ADDRESSE 0Bh, 8Bh, 10Bh, 18Bh)&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr style=&amp;quot;border:0px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;width:60px;&amp;quot;&amp;gt;R/W-x&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''GIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''PEIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIE'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''TMR0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''INT0IF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td style=&amp;quot;background:#f5f7ff;&amp;quot;&amp;gt;'''RBIF'''&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit7&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td colspan=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;td&amp;gt;Bit0&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*Bit 7 '''GIE''': Global Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle Interrupts&lt;br /&gt;
::0 = Deaktiviert alle Interrupts&lt;br /&gt;
*Bit 6 '''PEIE''': Peripheral Interrupt Enable Bit&lt;br /&gt;
::1 = Aktiviert alle peripheren Interrupts&lt;br /&gt;
::0 = Deaktiviert alle 	peripheren Interrupts&lt;br /&gt;
*Bit 5 '''TMR0IE''': TMR0 Overflow Interrupt Enable Bit (Overflow von Timer0 löst Interrupt aus)&lt;br /&gt;
::1 = Aktiviert den TMR0 Interrupt&lt;br /&gt;
::0 = Deaktiviert den TMR0 Interrupt&lt;br /&gt;
*Bit 4 '''INT0IE''': RB0/INT External Interrupt Enable Bit (Änderung an RB0 Pin löst Interrupt aus) *)&lt;br /&gt;
::1 = Aktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
::0 = Deaktiviert den RB0/INT Interrupt (Extern ausgelöst)&lt;br /&gt;
*Bit 3 '''RBIE''': RB Port On-Change-Interrupt Enable Bit (Änderung an PortB löst Interrupt aus) **)&lt;br /&gt;
::1 = Aktiviert den RB port on-change-interrupt&lt;br /&gt;
::0 = Deaktiviert den RB port on-change-interrupt&lt;br /&gt;
*Bit 2 '''TMR0IF''': TMR0 Overflow Interrupt Flag Bit&lt;br /&gt;
::1 = TMR0 Register ist Übergelaufen (muss per Software gelöscht werden)&lt;br /&gt;
::0 = TMR0 register ist nicht Übergelaufen&lt;br /&gt;
*Bit 1 '''INT0IF''': RB0/INT External Interrupt Flag Bit&lt;br /&gt;
::1 = Eine Änderung an RB0/INT Pin hat stattgefunden (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Eine Änderung an RB0/INT Pin hat nicht stattgefunden &lt;br /&gt;
*Bit 0 '''RBIF''': RB Port On-Change-Interrupt Flag bit&lt;br /&gt;
::1 = Mind. einer der Pins von RB7:RB4 hat sich geändert (muss per Software gelöscht werden)&lt;br /&gt;
::0 = Keiner der Pins von RB7:RB4 hat sich geändert&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* *) Die Flanke auf die reagiert werden soll, wird mit dem Bit OPTION_REG,INTEDG definiert. (steigende = 1 oder fallende = 0)&lt;br /&gt;
* **) Der Interrupt klingt verführerischer Weise so, als ob er den gesamten Port überwacht. Dabei reagiert er nur auf RB7:RB4!!!! Er kann aber den Prozessor vom &amp;quot;Schlaf&amp;quot; aufwecken (z.B. durch einen Tastendruck).&lt;br /&gt;
&lt;br /&gt;
==Speicherbankorganisation==&lt;br /&gt;
===Programmspeicher===&lt;br /&gt;
Die Mid-Range MCUs haben einen 2-8k großen Programmspeicher. Dieser hat aber in jeder Speicherzelle nicht 8, sondern 14 Bit - also genau die Länge eines Befehls. Die aktuelle Stelle im Programm wird im PC (Program Counter) verwaltet. Er speichert immer die aktuelle Adresse im Programmspeicher (wird im Code oft als &amp;quot;$&amp;quot; bezeichnet). Bei einem PIC mit 8k Adressen muss er also die Adressen 0000-1FFF speichern können. Daraus folgt die Größe von 13 Bit für den PC. Der Programmspeicher ist in mehrere Bänke geteilt, die alle 2k groß sind. Das Programm springt ohne zutun des Benutzers von einer in die Nächste. Wenn man aber selber springen will, muss man die Register PCLATH (Program Counter Latch High) und PCL (Program Counter Least Significant Byte) mit der Sprungadresse beschreiben.&lt;br /&gt;
&lt;br /&gt;
===Datenspeicher===&lt;br /&gt;
Der Datenspeicher besteht aus den Special Function Registern (SFR) und den General Purpose&lt;br /&gt;
Registern (GPR). Die SFRs sind für die Funktionen des PICs zuständig (Interrupts, Timer, ADCs, CCPM...) und die GPRs für die Speicherung von Variablen und Daten.&lt;br /&gt;
&lt;br /&gt;
Da immer nur 7 Bit der (Ziel)Adresse in einem Befehl gespeichert werden können, sind nur 7Fh (128d) Adressen im Datenbereich möglich. Deswegen wurde das &amp;quot;Banking&amp;quot; eingeführt. 2 Bit im Statusregister (welcher in allen Bänken der selbe ist und auch an der gleichen Stelle sitzt) geben die akutelle &amp;quot;Bank&amp;quot; an und sind nichts anderes als die 2 höchstwertigsten (MSB) Bits der Adresse. Damit lassen sich max. 4 Bänke ansprechen. Je nach PIC gibt es 2-4 Bänke. Die beiden Bits im Register STATUS heißen RP0 (STATUS&amp;lt;5&amp;gt;) und RP1 (STATUS&amp;lt;6&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|+ Wechseln der Bänke mit RP0 und RP1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|| RP1&lt;br /&gt;
|| RP0&lt;br /&gt;
|-&lt;br /&gt;
| Bank0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|-&lt;br /&gt;
| Bank2&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|0&lt;br /&gt;
|-&lt;br /&gt;
| Bank3&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Bild:PIC midrange register.JPG]]&lt;br /&gt;
# '''FETTE Register''' sind in allen PICs vorhanden&lt;br /&gt;
#  können je nach PIC unimplementierte Bereiche beinhalten - diese werden immer als 0 gelesen. (DATENBLATT!!)&lt;br /&gt;
# siehe 2&lt;br /&gt;
# Könnten je nach PIC auch nicht in Bank0 gemapped werden, sind dann eigenständige Register.&lt;br /&gt;
# je nach PIC kann es diese Bänke geben oder nicht geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Codeschnipsel ==&lt;br /&gt;
&lt;br /&gt;
Alle hier sich befindliche Programmbeispiele sind nur auf den PIC12... und PIC16... sicher lauffähig und müssen für PIC18... bei Problemen umgeschrieben werden. Weitere Beispiele befinden sich in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele&lt;br /&gt;
&lt;br /&gt;
=== Analog-Digital-Wandler (ADC) ===&lt;br /&gt;
&lt;br /&gt;
Viele PICs besitzen einen Analog-Digital-Wandler, der eine angelegte Spannung messen kann und diese als Zahl speichert.&lt;br /&gt;
&lt;br /&gt;
Es gibt AD-Wandler mit 8Bit bzw. 10Bit Auflösung, d.h. die Spannung an einem analogen Eingang wird linear 2^8=256 bzw. 2^10=1024 Werten zugeordnet.&lt;br /&gt;
Der höchste Wert, auch Referenzspannung genannt, (255 bzw. 1023; der Controller rechnet die Null auch mit) entspricht der Betriebsspannung des PICs oder wahlweise einer wählbaren Spannung, die an RA3 angelegt werden muss. Der niedrigste Wert entspricht 0 Volt.&lt;br /&gt;
&lt;br /&gt;
Mit dem Analog-Digital-Wandler kann man somit z.B. Sensoren auswerten, die mehr als zwei Zustände ausgeben (Beispiele: Temperatursensor, Helligkeitssensor, Entfernungssensoren usw.) oder Akkuspannungen messen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Bevor überhaupt gemessen werden kann, muss einiges eingestellt werden:&lt;br /&gt;
&lt;br /&gt;
* Eingangsverteilung Analog/Digital bzw.Referenzspannung (Betriebsspannung oder RA3)&lt;br /&gt;
die genauen Einstellungsmöglichkeiten entnehmen sie bitte dem Datenblatt ihres Controllers (Register ADCON1 Bank 1).&lt;br /&gt;
&lt;br /&gt;
* Wählen des Taktes für den ADC und Einschalten des ADCs&lt;br /&gt;
&lt;br /&gt;
Das Register ADCON0 besitzt 8 Bits, die folgendes bestimmen:&lt;br /&gt;
 Bit0 ADON - schaltet AD-Wandler ein oder aus (Strom sparen)&lt;br /&gt;
 Bit1 - nicht vorhanden&lt;br /&gt;
 Bit2 GO/Done - startet Wandlung / signalisiert, wann Umwandlung beendet ist.&lt;br /&gt;
 Bit3 CHS0 - Channel Select 0 wählt Eingang aus&lt;br /&gt;
 Bit4 CHS1 - Channel Select 1 wählt Eingang aus&lt;br /&gt;
 Bit5 CHS2 - Channel Select 2 wählt Eingang aus&lt;br /&gt;
 Bit6 ADCS0 - AD-Clock-Select wählt Takt&lt;br /&gt;
 Bit7 ADCS1 - AD-Clock-Select wählt Takt&lt;br /&gt;
&lt;br /&gt;
Kümmern wir uns zunächst um den Takt. Mit den zwei Bits ADCS0 und ADCS1 bestimmt man den Takt - hierbei gibt es vier Möglichkeiten:&lt;br /&gt;
&lt;br /&gt;
 ADCS1=0, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :2&lt;br /&gt;
 ADCS1=0, ADCS0=1 -&amp;gt; Taktfrequenz des PICs :8&lt;br /&gt;
 ADCS1=1, ADCS0=0 -&amp;gt; Taktfrequenz des PICs :32&lt;br /&gt;
 ADCS1=1, ADCS0=1 -&amp;gt; interner RC-Oszillator des ADCs verwenden&lt;br /&gt;
&lt;br /&gt;
Die Taktfrequenz des ADCs darf 625kHz nicht überschreiten, dementsprechend ist ADCS0 und ADCS1 zu wählen.&lt;br /&gt;
&lt;br /&gt;
Ist dies vollbracht, so kann man den AD-Wandler einschalten und das Go/Done-Bit löschen.&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,6 ;Takt für&lt;br /&gt;
 bsf ADCON0,7 ;ADC (OSC/32)&lt;br /&gt;
 bsf ADCON0,0 ;ADC einschalten, ADON=1&lt;br /&gt;
 bcf ADCON0,2 ;Go/Done-Bit zurücksetzen&lt;br /&gt;
&lt;br /&gt;
Nun ist der AD-Wandler bereit, Spannungen in Zahlen umzuwandeln.&lt;br /&gt;
Für eine Wandlung muss erst der entsprechende Eingang gewählt werden. Dafür sind die CHS0..CHS2-Bits zuständig:&lt;br /&gt;
&lt;br /&gt;
 CHS2 CHS1 CHS0  gewählter Eingang(falls vorhanden)&lt;br /&gt;
  0    0    0     RA0&lt;br /&gt;
  0    0    1     RA1&lt;br /&gt;
  0    1    0     RA2&lt;br /&gt;
  0    1    1     RA3&lt;br /&gt;
  1    0    0     RA5&lt;br /&gt;
  1    0    1     RE0&lt;br /&gt;
  1    1    0     RE1&lt;br /&gt;
  1    1    1     RE2&lt;br /&gt;
&lt;br /&gt;
 Achtung! RA4 ist kein analoger Eingang, folglich ist er oben nicht aufgelistet !!&lt;br /&gt;
&lt;br /&gt;
Codebeispiel:&lt;br /&gt;
&lt;br /&gt;
 bcf ADCON0,3 ;RA2 auswählen&lt;br /&gt;
 bsf ADCON0,4&lt;br /&gt;
 bcf ADCON0,5&lt;br /&gt;
&lt;br /&gt;
Als letztes muss die AD-Routine nur noch gestartet werden. Ist der AD-Wandler fertig, so löscht er das Bit wieder. Das Bit wird nun solange abgefragt, bis der AD-Wandler fertig ist. Den zugeordneten Wert findet man im Register 'ADRES'. &lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
    bsf ADCON0,2   ;start&lt;br /&gt;
 wa btfsz ADCON0,2 ;warten,bis es wieder low ist&lt;br /&gt;
    goto wa        ;noch nicht fertig&lt;br /&gt;
                   ;jetzt ist er fertig&lt;br /&gt;
    movf ADRES,W   ;ADRES in W verschieben, um damit gleich weiter zu arbeiten&lt;br /&gt;
&lt;br /&gt;
Die AD-Wandlung ist somit fertig. Liest man mehrere Werte von unterschiedlichen Eingängen ein und möchte diese miteinander vergleichen o.ä., sollte man die Zahlen von ADRES in anderen Registern zwischenspeichern.&lt;br /&gt;
&lt;br /&gt;
Desweiteren ist zu beachten, dass der Analog-Digital-Wandler eine gewisse Pause zwischen den Wandlungen benötigt, die sog. 'Aquisition Time'. Diese Zeitangabe entnehmen sie bitte ihrem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
mögliche Probleme:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert stark schwankende Werte&lt;br /&gt;
:-&amp;gt; Mögliche Ursachen dafür sind z.B. nicht stabile Betriebsspannung, falsche Zeiteinstellungen. Abhilfe schafft auch das mehrmalige Einlesen eines Eingangs. Auch können z.B. 8 Werte eingelesen werden und dann der Durchschnitt gebildet werden.&lt;br /&gt;
Evtl. kann ein Kondensator gegen Masse (z.B. 1nF) helfen; Wichtig ist auch eine kleine Verzögerung zwischen Kanalauswahl und Start der Wandlung. In dieser Zeit kann sich der interne Kondensator des ADC's aufladen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Die Spannung an einem Eingang wird erhöht, die Werte der anderen Eingänge werden aber auch beeinflusst.&lt;br /&gt;
:-&amp;gt; Dann sind Sie Opfer des sog. 'Ghostings' geworden (Werte 'scheinen durch', verschleißen). Die Werte der anderen Eingänge gehen mit, weil der interne Kondensator noch auf die Spannung des Vorgängers aufgeladen ist. Maßnahme: Aquisition Time erhöhen, Werte öfters abfragen, Pause zwischen Kanalauswahl und Start&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Der PIC liefert immer die gleichen Werte an einem Eingang, obwohl sich die angelegte Spannung ändert&lt;br /&gt;
:-&amp;gt; möglicherweise falsche Eingangsverteilung (ADCON1) eingestellt oder falschen Pin gewählt&lt;br /&gt;
&lt;br /&gt;
=== Hex Dec Wandlung ===&lt;br /&gt;
&lt;br /&gt;
Das ist ein Unterprogramm das mit &amp;quot;call Hex_Dec&amp;quot; aufgerufen wird. Es gibt 4 Register (A, B, C und D) mit jeweils 32 Bits, die aus jeweils 4 Register mit 8 Bits (z.B. fur A: A3, A2, A1 und A0) bestehen.&lt;br /&gt;
&lt;br /&gt;
        A3       A2       A1       A0&lt;br /&gt;
    .--------.--------.--------.--------.&lt;br /&gt;
    |76543210|76543210|76543210|76543210|&lt;br /&gt;
    '--------'--------'--------'--------'&lt;br /&gt;
    |                                   |&lt;br /&gt;
    |&amp;lt;----------- A Register ----------&amp;gt;|&lt;br /&gt;
&lt;br /&gt;
Sie müssen (wegen FSR) so wie im Code nacheinander liegen (die absoluten Adressen sind nicht wichtig). In das Register &amp;quot;A&amp;quot; wird die hex Zahl eingeschrieben und aus dem &amp;quot;D&amp;quot; die umgewandelte dec Zahl ausgelesen. A3,7 und D3,7 sind MSB und A0,0 und D0,0 sind LSB. Die &amp;quot;B&amp;quot; und &amp;quot;C&amp;quot; sind Hilfsregister. Das UP kann für kleinere als 32-bittige hex Zahlen modifiziert werden. Zum Beispiel für 16-bittige hex Zahlen bleiben nur Register A1,A0,B1,B0,C1,C0,D1,D0 und in den UPs werden in die Register und als X, folgende Zahlen eingeschrieben: HTmp -&amp;gt; 0x10 (Anzahl Bits der hex Zahl), ATmp -&amp;gt; 2 = X (Anzahl Bytes der hex Zahl). Es müssen auch die UPs &amp;quot;CClr&amp;quot;, &amp;quot;DClr&amp;quot; und &amp;quot;CopyCB&amp;quot; entsprechend der Registerlänge angepasst werden. Genauso kann natürlich das UP auch für längere hex Zahlen modifiziert werden.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;AddCB&amp;quot; addiert dezimal die 32- bittige Register C und B, das Ergebniss befindet sich in C.&lt;br /&gt;
Das UP &amp;quot;AddDC&amp;quot; addiert dezimal die 32-bittige Register D und C, das Ergebniss befindet sich in D.&lt;br /&gt;
&lt;br /&gt;
Die 32-bit Additionen werden in 4 Schritten wie folgt realisiert:&lt;br /&gt;
&lt;br /&gt;
C0+B0-&amp;gt;C0, C1+B1-&amp;gt;C1, C2+B2-&amp;gt;C2 und C3+B3-&amp;gt;C3 &lt;br /&gt;
&lt;br /&gt;
D0+C0-&amp;gt;D0, D1+C1-&amp;gt;D1, D2+C2-&amp;gt;D2 und D3+C3-&amp;gt;D3&lt;br /&gt;
&lt;br /&gt;
Die Flags &amp;quot;_Fcra&amp;quot;, &amp;quot;_Fcrp&amp;quot; und &amp;quot;_Fdca&amp;quot; steuern die alle nötigen Korrekturen.&lt;br /&gt;
&lt;br /&gt;
Die Wandlung wird in 32 Schritten laut folgender Formel durchgeführt:&lt;br /&gt;
&lt;br /&gt;
Zahl(d)=B0*2^0+B1*2^1+B2*2^2+B3*2^3+B4*2^4+B5*2^5+B6*2^6+B7*2^7+B8*2^8+B9*2^9+B10*2^10+B11*2^11+&lt;br /&gt;
&lt;br /&gt;
B12*2^12+B13*2^13+B14*2^14+B15*2^15+B16*2^16+B17*2^17+B18*2^18+B19*2^19+B20*2^20+B21*2^21+&lt;br /&gt;
&lt;br /&gt;
B22*2^22+B23*2^23+B24*2^24+B25*2^25+B26*2^26+B27*2^27+B28*2^28+B29*2^29+B30*2^30+B31*2^31&lt;br /&gt;
&lt;br /&gt;
Wobei B0 bedeutet den LSB und B31 den MSB der hex Zahl.&lt;br /&gt;
&lt;br /&gt;
Die dec Zahl wird im D Register durch &amp;quot;AddDC&amp;quot; gebildet. In dem C Register befindet sich immer die laufende 2^X. Am Anfang wird dort 1=2^0 geladen. Da die nächste zu addierende dec Zahl immer gleich 2* vorherige ist, wird sie einfach so berechnet, dass die aktuelle aus C Register ins B Register kopiert (&amp;quot;CopyCB&amp;quot;) und zu C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn das entsprechende Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0,0 dafür geprüft wird, wird das gesamte 32-bittige A Register nach jeder Addition &amp;quot;AddDC&amp;quot; um ein Bit mit &amp;quot;ARotRb&amp;quot; nach rechts rotiert. Die Flags &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fcrp&amp;quot; übertragen die Bits zwischen den 8 Bit Registern A0, A1, A2 und A3. Es würde zwar reichen, wenn das A Register nur verschoben würde, aber hier wurde Rotation gewählt, damit nach der Wandlung die hex Zahl im A Register unverändert steht. Weil die dec Zahl nur 8-stellig ist, darf die max. hex Zahl 99999999d = 5F5E0FFh sein.&lt;br /&gt;
&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3                         ;Überlauf (Fehler)&lt;br /&gt;
 ;.................................................................................. &lt;br /&gt;
 A3		EQU	0x20			;Register fürs Rechnen&lt;br /&gt;
 A2		EQU	0x21&lt;br /&gt;
 A1		EQU	0x22&lt;br /&gt;
 A0		EQU	0x23&lt;br /&gt;
 B3		EQU	0x24&lt;br /&gt;
 B2		EQU	0x25&lt;br /&gt;
 B1		EQU	0x26&lt;br /&gt;
 B0		EQU	0x27&lt;br /&gt;
 C3		EQU	0x28&lt;br /&gt;
 C2		EQU	0x29&lt;br /&gt;
 C1		EQU	0x2A&lt;br /&gt;
 C0		EQU	0x2B&lt;br /&gt;
 D3		EQU	0x2C&lt;br /&gt;
 D2		EQU	0x2D&lt;br /&gt;
 D1		EQU	0x2E&lt;br /&gt;
 D0		EQU	0x2F&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Flags		EQU	0x30&lt;br /&gt;
 ATmp		EQU	0x31			;Schleifenzähler&lt;br /&gt;
 HTmp		EQU	0x32                    ;Schleifenzähler&lt;br /&gt;
 RTmp		EQU	0x33                    ;Zwischenspeicher&lt;br /&gt;
 ;..................................................................................&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== EEPROM ===&lt;br /&gt;
&lt;br /&gt;
Alle PICs besitzen EEPROM in dem je nach Typ können 64 bis 256 Databytes abgespeichert werden. Die Adressierung des EEPROMs fängt immer mit 0x00 an. Hier werden nur geprüfte UPs kurz erklärt. Die ersten zwei brauchen nur ein Register &amp;quot;Temp&amp;quot; für Schleifenzähler, dessen Name, falls im Programm schon existiert, geändert werden muss. Die Adresse im EEPROM ist gleich der Adresse im RAM.&lt;br /&gt;
&lt;br /&gt;
EEPROM beschreiben: &lt;br /&gt;
&lt;br /&gt;
 EEWrite         movlw	0x20	    ; ab der RAM Adresse wird in EEPROM abgespeichert&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4           ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	    ; Schleifenzähler&lt;br /&gt;
 EEWLoop         call	EEWrite1&lt;br /&gt;
 		incf	FSR,1	    ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EEWLoop&lt;br /&gt;
 		return	&lt;br /&gt;
 &lt;br /&gt;
 EEWrite1        bcf	INTCON,GIE  ; Interrupts sperren&lt;br /&gt;
 		movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0  ; auf Bank1 umschalten&lt;br /&gt;
 		movwf	EEADR       ; EEPROM Adresse&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	EEDATA      ; EEPROM Data&lt;br /&gt;
 		bsf	EECON1,WREN&lt;br /&gt;
 		movlw	0x55&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		movlw	0xAA&lt;br /&gt;
 		movwf	EECON2&lt;br /&gt;
 		bsf	EECON1,WR&lt;br /&gt;
 		bcf	EECON1,WREN&lt;br /&gt;
 		btfsc	EECON1,WR&lt;br /&gt;
 		goto	$-1          ; warten bis WR=0&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		bsf	INTCON,GIE   ; Interrupts erlauben&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
EEPROM lesen und zurück in RAM schreiben: &lt;br /&gt;
 &lt;br /&gt;
 EERead          movlw	0x20	     ; ab der Adresse wird aus EEPROM in RAM abgelegt	&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movlw	4	     ; soviel Bytes&lt;br /&gt;
 		movwf	Temp	     ; Schleifenzähler&lt;br /&gt;
 EERLoop         call	EERead1&lt;br /&gt;
 		incf	FSR,1        ; nächste Adresse&lt;br /&gt;
 		decfsz	Temp,1&lt;br /&gt;
 		goto	EERLoop&lt;br /&gt;
 		return&lt;br /&gt;
 &lt;br /&gt;
 EERead1         movf	FSR,0&lt;br /&gt;
 		bsf	STATUS,RP0   ; auf Bank1 umschalten &lt;br /&gt;
 		movwf	EEADR        ; EEPROM Adresse&lt;br /&gt;
 		bsf	EECON1,RD&lt;br /&gt;
 		movf	EEDATA,0     ; EEPROM Data&lt;br /&gt;
 		bcf	STATUS,RP0   ; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movwf	INDF&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
Tabelle im EEPROM mit MPASM Direktive &amp;quot;de&amp;quot; erstellen:&lt;br /&gt;
&lt;br /&gt;
 		org             0x2100             ; EEPROM initialisieren&lt;br /&gt;
                                                    ; nachfolgend als Kommentar die EEPROM Adressen&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	de      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	de      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	de      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	de      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	de      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	de      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	de      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	de      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   usw.&lt;br /&gt;
&lt;br /&gt;
Wenn die Tabelle sich im Quellcode befindet, wird sie beim brennen des PICs in EEPROM eigeschrieben.&lt;br /&gt;
&lt;br /&gt;
Das Lesen eines Strings muss ab entsprechender EEPROM Adresse (z.B. für &amp;quot;MHz&amp;quot; -&amp;gt; 0x04) anfangen und auf dem Wert 0x00, der hier als Stringende dient, enden. Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator für Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adresse &amp;quot;0x2100&amp;quot; in der &amp;quot;org&amp;quot; Direktive hat mit der Adresse im Programmspeicher nichts zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Interrupts ===&lt;br /&gt;
&lt;br /&gt;
Das Programm misst eine Frequenz an T0CKI Pin, wurde für den PIC16F628 geschrieben und in einem genauen Frequenzzähler angewendet. Es ist nur auf PICs lauffähig, die mindestens zwei Timer besitzen.&lt;br /&gt;
&lt;br /&gt;
Es gibt nur ein Messbereich von 1 Hz bis 99999999 Hz mit gleicher Auflösung 1 Hz, deswegen ist kein Dezimalpunkt benutzt. Für einen kompletten Frequenzzähler ist nur noch ein Eingangsverstärker nötig.&lt;br /&gt;
&lt;br /&gt;
Benötigte Hardware: Widerstand 470 Ohm zwischen der Frequenzquelle und TOCKI Pin (A4). &lt;br /&gt;
&lt;br /&gt;
Die Ausgabe erfolgt auf ein 2x8 standard Zeichendisplay. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts außer warten auf ein Interrupt von Timer0 bzw. Timer1. Die ISR benutzt keine Register vom UPs und deshalb müssen W- und STATUS Register nicht gesichert und wiederhergestellt werden.&lt;br /&gt;
&lt;br /&gt;
Da der Timer0 nicht, wie der Timer1 durch ein Flag gestartet und gestoppt werden kann, wird es durch setzen und löschen des Bits für TOCKI (A4) Pin im TRISA Register, genauso wie in der AN592 vom Microchip, gemacht.&lt;br /&gt;
&lt;br /&gt;
Der Timer 0 zählt die Impulse am TOCKI Pin (A4) in der Zeit, die vom Timer 1 bestimmt wird.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um zwei zusätzliche Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TMR0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebnis, der als hex Zahl in den Register A3 (MSB),A2, A1, und A0 (LSB) steht. Nach der &amp;quot;Hex_Dec&amp;quot; Wandlung kann die Frequenz aus den Register D3 (MSB), D2, D1 und D0 (LSB) an einem beliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Die Quarzfrequenz 7,3728 MHz wurde gewählt, weil sie am nächsten der temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist.  Die Quarzfrequenz muß nicht genau sein, da der Frequenzzähler lässt sich sehr genau mit den Werten von TMR1H und TMR1L &amp;quot;trimmen&amp;quot;, die vor dem Start des Timers 1 geladen werden.&lt;br /&gt;
&lt;br /&gt;
Für sehr genaue Messungen wird empfohlen als Taktfrequenz für den Timer1, die Trägerfrequenz eines nächsten LW Senders (z.B. DLF 153 bzw. 207 kHz) zu nutzen. Die Genauigkeit der Frequenz ist ca. 1E-11 und geprüfter Empfänger kann laut der Skizze in [[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=13706&amp;amp;highlight=frequenzz%E4hler]] nachgebaut werden. In dem Fall müssen die Register vom Timer1 (TMR1H und TMR1L) vor seinem Start mit entsprechenden Werten geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Hier wird die Messzeit 1 s genutzt und die Frequenz wird mit einer Auflösung von 1 Hz gemessen. Die Messzeit beträgt 3*10000h+(FFFFh-7BFFh) Timertakten. Für den Quarz 7,372800 MHz und Prescaler=8, wird der Takt von Timer1 gleich 7372800/4*8=230400 Hz. Deswegen wird der Timer1 beim Starten mit ca. 7BFFh geladen und nach dem 4. Überlauf gestoppt. Die in TMR1H und TMR1L praktisch geladene Werte unterscheiden sich ein bißchen von berechneten, weil die Quarzfrequenz fast nie genau bis auf 1 Hz stimmt.&lt;br /&gt;
&lt;br /&gt;
Für z.B. 20 MHz Quarz werden 10 Überläufe des Timers benötigt und er wird beim Start mit 7697h geladen, da 1s gleich 9x10000h+(FFFFh-7697h) Timertakten ist.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Init&amp;quot; muss eventuell für ein anderes Display die Initialisierung des Displaykontrollers geändert werden.&lt;br /&gt;
&lt;br /&gt;
In dem Program wurden unveränderte UPs verwendet, die näher in [[#Hex Dec Wandlung|Hex Dec Wandlung]] und [[#Matrix|Matrix]] erklärt sind.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F628&lt;br /&gt;
 	include &amp;quot;P16F628.inc&amp;quot;&lt;br /&gt;
 	__CONFIG     _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _MCLRE_OFF &amp;amp; _HS_OSC &amp;amp; _BODEN_OFF &amp;amp; _LVP_OFF&lt;br /&gt;
 &lt;br /&gt;
 ;	TOCKI	PORTA,4				;I Frequenzeingang&lt;br /&gt;
 ;	DB4	PORTB,0				;O Display Data Bit 4&lt;br /&gt;
 ;	DB5	PORTB,1				;O Display Data Bit 5&lt;br /&gt;
 ;	DB6	PORTB,2				;O Display Data Bit 6&lt;br /&gt;
 ;	DB7	PORTB,3				;O Display Data Bit 7&lt;br /&gt;
 #define	_RS	PORTB,4				;O Display RS&lt;br /&gt;
 #define	_E	PORTB,5				;O Display Enable&lt;br /&gt;
 #define	_C	STATUS,C&lt;br /&gt;
 #define	_Z	STATUS,Z&lt;br /&gt;
 #define	_DC	STATUS,DC&lt;br /&gt;
 #define	_RP0	STATUS,RP0&lt;br /&gt;
 #define	_Fcra	Flags,0&lt;br /&gt;
 #define	_Fcrp	Flags,1&lt;br /&gt;
 #define	_Fdca	Flags,2&lt;br /&gt;
 #define	_Ferr	Flags,3				;Überlauf (Fehler)&lt;br /&gt;
 #define	_Frs	Flags,4&lt;br /&gt;
 #define	_Fnz	Flags,5&lt;br /&gt;
 A3		equ	0x20			;Register fürs Rechnen Hex_Dec&lt;br /&gt;
 A2		equ	0x21&lt;br /&gt;
 A1		equ	0x22&lt;br /&gt;
 A0		equ	0x23&lt;br /&gt;
 B3		equ	0x24&lt;br /&gt;
 B2		equ	0x25&lt;br /&gt;
 B1		equ	0x26&lt;br /&gt;
 B0		equ	0x27&lt;br /&gt;
 C3		equ	0x28&lt;br /&gt;
 C2		equ	0x29&lt;br /&gt;
 C1		equ	0x2A&lt;br /&gt;
 C0		equ	0x2B&lt;br /&gt;
 D3		equ	0x2C&lt;br /&gt;
 D2		equ	0x2D&lt;br /&gt;
 D1		equ	0x2E&lt;br /&gt;
 D0		equ	0x2F&lt;br /&gt;
 Tmp		equ	0x30                    ;Register, die für Displayausgabe&lt;br /&gt;
 Tmp1		equ	0x31                    ;vorläufig benutzt werden&lt;br /&gt;
 Flags		equ	0x32&lt;br /&gt;
 ATmp		equ	0x33			;vorläufige Schleifenzähler&lt;br /&gt;
 HTmp		equ	0x34&lt;br /&gt;
 RTmp		equ	0x35                    ;Zwischenspeicher&lt;br /&gt;
  		ORG	0x0000&lt;br /&gt;
 		call	Init                    ;alles initialisieren&lt;br /&gt;
 Main		goto	Main                    ;und in die leere endlose Schleife springen &lt;br /&gt;
 		ORG	0x0004			;hier fängt ISR (interrupt service routine) an&lt;br /&gt;
 		bcf	INTCON,GIE		;alle interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 überlaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;ja, Timer0 interrupt flag löschen und bearbeiten&lt;br /&gt;
 	 	movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2 durch Addition&lt;br /&gt;
 		btfsc	_C                      ;um Überlauf von A2 zu erkennen und&lt;br /&gt;
 		incf	A3,1			;increment A3, wenn A2 überlaufen ist&lt;br /&gt;
 CheckTMR1	btfss	PIR1,TMR1IF		;ist Timer1 überlaufen ?&lt;br /&gt;
 		retfie				;nein, dann ISR beenden und interrupts erlauben&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&lt;br /&gt;
 		call	Multip                  ;Interrupts vom Timer1 im UP &amp;quot;Multip&amp;quot; zählen&lt;br /&gt;
 		retfie				;ISR beenden und interrupts erlauben&lt;br /&gt;
 Multip		incf	Tmp,1			;Interruptszähler von Timer1 erhöhen&lt;br /&gt;
 		btfss	Tmp,2			;schon 4.interrupt?&lt;br /&gt;
 		return				;nein, dann zurück&lt;br /&gt;
 		bsf	_RP0			;ja, weiter&lt;br /&gt;
 		movf	TRISA,0			;stopp Timer0 usw.&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 GetFreq		movf	TMR0,0			;Prescaler ins Register A0 kopieren&lt;br /&gt;
 		movwf	A1&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		clrf	ATmp&lt;br /&gt;
 FToggle		incf	ATmp,1&lt;br /&gt;
 		bsf	_RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	RTmp,0&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec                 ;Messergebnis auf Decimal wandeln&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		call	DispFrq                 ;eventuell eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		return&lt;br /&gt;
 AClr		clrf	A0			;Register A löschen&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A3&lt;br /&gt;
 		return&lt;br /&gt;
 TMRStart	movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;und laden&lt;br /&gt;
 		movlw	0x7B			;berechneter Wert: TMR1H=7Bh&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		movlw	0xFB			;berechneter Wert: TMR1L=FFh&lt;br /&gt;
 		movwf	TMR1L&lt;br /&gt;
 		bsf	_RP0			;start Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4)als Eingang&lt;br /&gt;
 		bcf	_RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 Hex_Dec 	call	DClr			;Hex&amp;gt;A, D&amp;gt;Dec&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movlw	0x20			;32 bit Hex &amp;gt; 32 bit Dec (8 Stellen)&lt;br /&gt;
 		movwf	HTmp&lt;br /&gt;
 HexDecL 	btfsc	A0,0&lt;br /&gt;
 		call	AddDC&lt;br /&gt;
 		call	CopyCB&lt;br /&gt;
 		call	AddCB&lt;br /&gt;
 		call	ARotRb&lt;br /&gt;
 		decfsz	HTmp,1&lt;br /&gt;
 		goto	HexDecL&lt;br /&gt;
 		return&lt;br /&gt;
 DClr		clrf	D0&lt;br /&gt;
 		clrf	D1&lt;br /&gt;
 		clrf	D2&lt;br /&gt;
 		clrf	D3&lt;br /&gt;
 		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&lt;br /&gt;
  		return&lt;br /&gt;
 CopyCB		movf	C0,0&lt;br /&gt;
 		movwf	B0&lt;br /&gt;
 		movf	C1,0&lt;br /&gt;
 		movwf	B1&lt;br /&gt;
 		movf	C2,0&lt;br /&gt;
 		movwf	B2&lt;br /&gt;
 		movf	C3,0&lt;br /&gt;
 		movwf	B3&lt;br /&gt;
 		return&lt;br /&gt;
 AddCB		movlw	B0			;C+B&amp;gt;C&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		goto	AddR&lt;br /&gt;
 AddDC		movlw	C0			;D+C&amp;gt;D&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 AddR		bcf	_Ferr			;Addiere zwei Register&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		movlw	4			;X=4 Bytes lang&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 AddRL		bcf	_Fdca&lt;br /&gt;
 		bcf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		movwf	RTmp&lt;br /&gt;
 		movlw	4                       ;X=4 &lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfss	_Fcrp&lt;br /&gt;
 		goto	AddRN&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 AddRN		movf	RTmp,0&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		call	DecCor&lt;br /&gt;
 		btfss	_Fdca&lt;br /&gt;
 		goto	AddCor1&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 AddCor1 	btfss	_Fcra&lt;br /&gt;
 		goto	AddCor2&lt;br /&gt;
 		movlw	0x60&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor2 	movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0xA0&lt;br /&gt;
 		btfss	_Z&lt;br /&gt;
 		goto	AddCor3&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 AddCor3 	bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		movlw	5                       ;X+1=5&lt;br /&gt;
 		subwf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	AddRL&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Ferr&lt;br /&gt;
 		return&lt;br /&gt;
 DecCor		btfsc	_DC			;dezimale Korrektur (equ &amp;quot;DAW&amp;quot; bei PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
 ARotRb		movlw	A3			;rotiere A Register 1 Bit rechts&lt;br /&gt;
 		movwf	FSR			&lt;br /&gt;
 RRotRb		movlw	4			;rotiere X=4 Bytes&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	A0,0&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 RRotRbL 	bcf	_Fcra&lt;br /&gt;
 		btfsc	INDF,0&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		bcf	_C&lt;br /&gt;
 		btfsc	_Fcrp&lt;br /&gt;
 		bsf	_C&lt;br /&gt;
 		rrf	INDF,1&lt;br /&gt;
 		bcf	_Fcrp&lt;br /&gt;
 		btfsc	_Fcra&lt;br /&gt;
 		bsf	_Fcrp&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	RRotRbL&lt;br /&gt;
 		return&lt;br /&gt;
 DispFrq		bcf	_Fnz			;Frequenz anzeigen (8 Ziffern)&lt;br /&gt;
 		call	Fst                     ;mit Unterdrückung der führenden Nullen &lt;br /&gt;
 		movlw	3&lt;br /&gt;
 		movwf	ATmp&lt;br /&gt;
 		movlw	D3&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		swapf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	ATmp,1&lt;br /&gt;
 		goto	$-18&lt;br /&gt;
 		swapf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	$+2&lt;br /&gt;
 		bsf	_Fnz&lt;br /&gt;
 		btfss	_Fnz&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movf	D0,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		call	Snd                      ;zweite Zeile&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;k&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;^&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 	        movlw	&amp;quot;H&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;z&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		return&lt;br /&gt;
 Fst		movlw	0x80			;Adresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 Snd		movlw	0xC0			;Adresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			;Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			;RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Val		movwf	Tmp1&lt;br /&gt;
 	        swapf	Tmp1,0&lt;br /&gt;
 		call	Num&lt;br /&gt;
 		movf	Tmp1,0&lt;br /&gt;
 Num		andlw	0x0F&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	Tmp,0&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A			;ASCII 0-F&lt;br /&gt;
 Char		movwf	Tmp			;Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			;RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			;zuerst High Nibble&lt;br /&gt;
 	        andlw	0x0F&lt;br /&gt;
 	        movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			;RS Flag an Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 	        bsf	_E			;Enable erzeugen&lt;br /&gt;
 	        bcf	_E&lt;br /&gt;
 		movf	Tmp,0			;Low Nibble&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	PORTB			;an Port (Display) schicken&lt;br /&gt;
 Enab		btfsc	_Frs			;RS Flag in Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			;Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x30			;Verzögerung min. ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Register vorm Start löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
 		clrf	Tmp&lt;br /&gt;
 		clrf	TMR0&lt;br /&gt;
 		call    AClr &lt;br /&gt;
 		bsf	_RP0			;Bank 1&lt;br /&gt;
 		movlw	0xFF&lt;br /&gt;
 		movwf	TRISA			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		clrf    TRISB                   ;und alle PORTB Pins als Ausgänge&lt;br /&gt;
 	        movlw	0xE7			;Takt für Timer0 vom T0CKI Pin usw.&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	_RP0			;Bank 0&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		call	TMRStart		;beide Timer starten&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
 		movlw	2			;Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28			;4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			;display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			;incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad bzw. Drehencoder ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad bzw. Drehencoder aus und setzt, je nach Drehrichtung und sein Anschluss an PORT (PORTB,0 und PORTB,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Diese Flags können z.B. für Inkrementierung und Dekrementierung von Zählern dienen. &lt;br /&gt;
&lt;br /&gt;
Die Hardware:&lt;br /&gt;
&lt;br /&gt;
                                    Mausrad bzw. Drehencoder&lt;br /&gt;
                                            .-------.&lt;br /&gt;
                                            |     o---&amp;gt; PORTB,0&lt;br /&gt;
                                         +----o---- |&lt;br /&gt;
                                         |  |     o---&amp;gt; PORTB,1&lt;br /&gt;
                                        === '-------'&lt;br /&gt;
                                        GND&lt;br /&gt;
&lt;br /&gt;
Es müssen die internen pull-ups vom PORTB aktiviert werden. Wenn das Mausrad bzw. Drehencoder an anderen PORT angeschlossen wird, werden externe pull-ups (z.B. 10 kOhm) benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Zum Auswerten werden 4 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot;, &amp;quot;MausC&amp;quot; und &amp;quot;Flags&amp;quot; gebraucht, die im gesamten Programm definiert werden müssen. Das UP &amp;quot;Delay&amp;quot; soll ca. 10ms dauern. Dafür kann eine Warteschleife oder zusammengesetzte UPs (z.B. Displayausgabe) mit solcher Ausführungszeit benutzt werden. &lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eingelesen, die alle Bits außer 0 und 1 durch &amp;quot;and&amp;quot; Funktion gelöscht und in den Register &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; gespeichert. Nach ca. 10ms wird das gleiche gemacht und im Register &amp;quot;MausA&amp;quot; gespeichert. Der Wert aus &amp;quot;MausA&amp;quot; wird mit dem vorherigen aus &amp;quot;MouseC&amp;quot; durch &amp;quot;xor&amp;quot; verglichen. Sind sie nicht identisch, wird je nach dem Wert &amp;quot;X&amp;quot; (0, 1, 2, bzw. 3) im &amp;quot;MausB&amp;quot; in das entsprechende UP &amp;quot;MouseX&amp;quot; gesprungen. Sonst, wenn &amp;quot;MausA&amp;quot;=&amp;quot;MausC&amp;quot;, wird zum Aufrufer zurückgekehrt.&lt;br /&gt;
&lt;br /&gt;
In einem UP &amp;quot;MouseX&amp;quot; wird der letzte Wert im &amp;quot;MausA&amp;quot; ermittelt und nach der Kombination der Werte im &amp;quot;MausB&amp;quot; und &amp;quot;MausA&amp;quot; (01 bzw. 02, 10 bzw. 13, 20 bzw. 23 oder 31 bzw. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot; gesetzt. Anschließend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detaillierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTB-&amp;gt;W&lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausB&lt;br /&gt;
                                              W-&amp;gt;MausC&lt;br /&gt;
                                            Warten 10ms&lt;br /&gt;
                                              PORTB-&amp;gt;W &lt;br /&gt;
                                             3 and W-&amp;gt;W&lt;br /&gt;
                                              W-&amp;gt;MausA&lt;br /&gt;
                                         W xor MausC-&amp;gt;MausC&lt;br /&gt;
                                                _Z=1 ? J &amp;gt; return&lt;br /&gt;
                                                  N&lt;br /&gt;
                                                  V&lt;br /&gt;
                                             MausB-&amp;gt;MausB&lt;br /&gt;
                 .--------------------------&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                                N &lt;br /&gt;
                 |                                V&lt;br /&gt;
                 |                            MausB-&amp;gt;W&lt;br /&gt;
                 |                             1-W-&amp;gt;W&lt;br /&gt;
                 |                     .----&amp;lt; J _Z=1 ?&lt;br /&gt;
                 |                     |          N&lt;br /&gt;
                 |                     |          V&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W&lt;br /&gt;
                 |                     |       2-W-&amp;gt;W&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;---------------------------.&lt;br /&gt;
                 |                     |          N                                  |&lt;br /&gt;
                 |                     |          V                                  |&lt;br /&gt;
                 |                     |      MausB-&amp;gt;W                               |&lt;br /&gt;
                 |                     |       3-W-&amp;gt;W                                |&lt;br /&gt;
                 |                     |        _Z=1 ? J &amp;gt;-----.                     |&lt;br /&gt;
                 |                     |          N            |                     |&lt;br /&gt;
                 |                     |          V            |                     |&lt;br /&gt;
                 |                     |        return         |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
                 |                     |                       |                     |&lt;br /&gt;
     Mouse0      V        Mouse1       V           Mouse3      V        Mouse2       V&lt;br /&gt;
             MausA-&amp;gt;W             MausA-&amp;gt;MausA             MausA-&amp;gt;W             MausA-&amp;gt;MausA&lt;br /&gt;
              1-W-&amp;gt;W                   V                    1-W-&amp;gt;W                   V&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Fdec |         setze _Finc |           setze _Finc |         setze _Fdec |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
             MausA-&amp;gt;W              MausA-&amp;gt;W                MausA-&amp;gt;W              MausA-&amp;gt;W &lt;br /&gt;
              2-W-&amp;gt;W                3-W-&amp;gt;W                  2-W-&amp;gt;W                3-W-&amp;gt;W&lt;br /&gt;
            _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.           _Z=1 ? N &amp;gt;--.         _Z=1 ? N &amp;gt;--.&lt;br /&gt;
                 J      |              J      |                J      |              J      |&lt;br /&gt;
                 V      |              V      |                V      |              V      |&lt;br /&gt;
            setze _Finc |         setze _Fdec |           setze _Fdec |         setze _Finc |&lt;br /&gt;
                 V&amp;lt;-----´              V&amp;lt;-----´                V&amp;lt;-----´              V&amp;lt;-----´&lt;br /&gt;
               return                return                  return                return&lt;br /&gt;
&lt;br /&gt;
und Quellcode:&lt;br /&gt;
&lt;br /&gt;
 Mouse		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausB&lt;br /&gt;
 		movwf	MausC&lt;br /&gt;
 		call	Delay		; ca. 10 ms&lt;br /&gt;
 		movf	PORTB,0&lt;br /&gt;
 		andlw	3&lt;br /&gt;
 		movwf	MausA&lt;br /&gt;
 		xorwf	MausC,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movf	MausB,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse0&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse1&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse2&lt;br /&gt;
 		movf	MausB,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		goto	Mouse3&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse0		movf	MausA,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse1		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse2		movf	MausA,1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		return&lt;br /&gt;
 Mouse3		movf	MausA,1&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Finc&lt;br /&gt;
 		movf	MausA,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	_Z&lt;br /&gt;
 		bsf	_Fdec&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
=== LCD Displays ===&lt;br /&gt;
&lt;br /&gt;
==== Matrix ====&lt;br /&gt;
&lt;br /&gt;
Ein Programm zum Ansteuern von Matrixdisplays im 4-bit Modus. Das Display ist an 6 Pins eines Ports (hier: B) angeschlossen. In diesem Beispielprogramm wurde 2x16 Zeichen Display verwendet, das Programm kann aber für andere Displays modifiziert werden. Für andere Taktfrequenzen muss lediglich nur die Verzögerung vom &amp;quot;Del&amp;quot; geändert werden. Zum Beispiel für 20 MHz Quarz, anstatt 0x10 auf 0x50. Die im &amp;quot;Main&amp;quot; ans Display geschickte Zeichen können beliebig geändert werden.&lt;br /&gt;
&lt;br /&gt;
Das Display wird wie folgt an den PIC16F84A angeschlossen:&lt;br /&gt;
&lt;br /&gt;
                                  VCC&lt;br /&gt;
                                   +&lt;br /&gt;
                                   |    .-------.&lt;br /&gt;
                                   +----|2      |&lt;br /&gt;
                                     +--|1,3,5  |&lt;br /&gt;
                                     |  |       |&lt;br /&gt;
                                    === |       |&lt;br /&gt;
                      .-------.     GND |       |&lt;br /&gt;
                      |  B4 10|---------|4  RS  |&lt;br /&gt;
                      |  B5 11|---------|6  E   |&lt;br /&gt;
                      |       |         |       |&lt;br /&gt;
                      |       |         |7  DB0 |&lt;br /&gt;
                      |       |         |8  DB1 |&lt;br /&gt;
                      |       |         |9  DB2 |&lt;br /&gt;
                      |       |         |10 DB3 |&lt;br /&gt;
                      |   B0 6|---------|11 DB4 |&lt;br /&gt;
                      |   B1 7|---------|12 DB5 |&lt;br /&gt;
                      |   B2 8|---------|13 DB6 |&lt;br /&gt;
                      |   B3 9|---------|14 DB7 |&lt;br /&gt;
                      '-------'         '-------'&lt;br /&gt;
                      PIC16F84A          DISPLAY&lt;br /&gt;
&lt;br /&gt;
 ;	Display Test im 4-bit Modus&lt;br /&gt;
 	LIST      P=16F84a&lt;br /&gt;
 	include &amp;quot;P16F84a.inc&amp;quot;   		; 4.000 MHz&lt;br /&gt;
 	__CONFIG _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 ;		DB4	PORTB,0 		; Display Data-Bits&lt;br /&gt;
 ;		DB5	PORTB,1&lt;br /&gt;
 ;		DB6	PORTB,2&lt;br /&gt;
 ;		DB7	PORTB,3&lt;br /&gt;
 #define 	_RS	PORTB,4        		; Display RS&lt;br /&gt;
 #define 	_E	PORTB,5        		; Display Enable&lt;br /&gt;
 #define 	_Frs	Flags,0        		; RS Flag&lt;br /&gt;
 Tmp		equ	0x20	&lt;br /&gt;
 Flags		equ	0x21&lt;br /&gt;
 		org	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		call	Fst&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;D&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;p&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;l&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;a&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;y&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;T&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;e&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		call	Snd&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;m&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;4&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;-&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;b&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;i&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;t&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot; &amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;M&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;o&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;d&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;u&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		movlw	&amp;quot;s&amp;quot;&lt;br /&gt;
 		call	Char&lt;br /&gt;
 		sleep&lt;br /&gt;
 Fst		movlw	0x80			; Anfangsadresse der ersten Zeile&lt;br /&gt;
 		goto	Cmd			&lt;br /&gt;
 Snd		movlw	0xC0			; Anfangsadresse der zweiten Zeile&lt;br /&gt;
 Cmd		movwf	Tmp			; Befehl ins Tmp laden&lt;br /&gt;
 		bcf	_Frs			; RS=0&lt;br /&gt;
 		goto	Send&lt;br /&gt;
 Char		movwf	Tmp			; Zeichen ins Tmp laden&lt;br /&gt;
 		bsf	_Frs			; RS=1&lt;br /&gt;
 Send		swapf	Tmp,0			; zuerst High Nibble (ab jetzt Low Nibble)&lt;br /&gt;
 		andlw	0x0F                    ; (aktuelles Low Nibble ausblenden)&lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 		btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 		movf	Tmp,0			; Low Nibble&lt;br /&gt;
 		andlw	0x0F                    ; (High Nibble ausblenden) &lt;br /&gt;
 		movwf	PORTB			; an Port (Display) schicken&lt;br /&gt;
 Enab            btfsc	_Frs			; RS Flag ans Port kopieren&lt;br /&gt;
 		bsf	_RS&lt;br /&gt;
 		bsf	_E			; Enable erzeugen&lt;br /&gt;
 		bcf	_E&lt;br /&gt;
 Del		movlw	0x10			; Verzögerung ca. 50µs&lt;br /&gt;
 		movwf	Tmp&lt;br /&gt;
 		decfsz	Tmp,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTB			; PortB initialisieren&lt;br /&gt;
 		bsf	STATUS,RP0              ; Bank 1 &lt;br /&gt;
 		clrf	TRISB                   ; alle Pins als Ausgänge&lt;br /&gt;
 		bcf	STATUS,RP0              ; Bank 0&lt;br /&gt;
 		bcf	_Frs&lt;br /&gt;
  		movlw	2			; Display auf 4-bit umschalten und initialisieren&lt;br /&gt;
 		movwf	PORTB&lt;br /&gt;
 		call	Enab&lt;br /&gt;
 		movlw	0x28                    ; 4 bit, 2 Zeilen, 5x7 Punkten&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	0x0C			; display an, cursor aus, nicht blinken&lt;br /&gt;
 		call	Cmd&lt;br /&gt;
 		movlw	6			; incrementieren, nicht schieben&lt;br /&gt;
 		goto	Cmd&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
==== Grafik ====&lt;br /&gt;
&lt;br /&gt;
2-pin Schnittstelle und ein Testprogramm für Grafikdisplay HYUNDAI HP12542R_DYO [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=20277]]&lt;br /&gt;
&lt;br /&gt;
==== Handy ====&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und ein Testprogramm für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
==== 7-Segment mit 3 Backplanes ohne Kontroller ====&lt;br /&gt;
&lt;br /&gt;
Eine Schnittstelle und ein Testprogramm für LPH2673-1 von Pollin:&lt;br /&gt;
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26005&amp;amp;highlight=lph26731]]&lt;br /&gt;
&lt;br /&gt;
= High-End (PIC18...)=&lt;br /&gt;
&lt;br /&gt;
Als High-End werden alle 8-bit PIC18F... klasiffieziert, die Befehlslänge 16-Bit, also 2 Bytes haben. Ihr Befehlsatz enthält insgesamt 75 Befehle.&lt;br /&gt;
&lt;br /&gt;
Es werden nur nötige fürs Erstellen von ASM Programmen spezifische Unterschiede behandelt, die in der Praxis Probleme für Umsteiger von Basic-Line und Mid-Range bereiten können. Wenn sich jemand ausschliesslich mit PIC18F... beschäftigen will, wird sich keine Unterschiede merken müssen, da ausser erweitertem Befehlsatz die Programme von ihrer Struktur identisch sind. Genaue Parameter für bestimmten PIC befinden sich im entsprechendem Datenblatt.&lt;br /&gt;
&lt;br /&gt;
== Hardware ==&lt;br /&gt;
&lt;br /&gt;
Weil die PIC18F... für einige Anwendungen schneller als Mid-Range laufen müssen, wurde bei Takterzeugung eine PLL-Option beim Oszillator zugefügt, die aus standard Quarzen (z.B. 12 MHz) durch Multiplikation mal 4 eine Taktfrequenz für CPU 12 MHz (z.B. für USB) erzeugt. Weil die Frequenz des Oszilators für interne Taktung der CPU durch 4 geteilt ist, ermöglichst diese Option, dass die CPU mit Oscillatorfrequenz, also bei z.B. 10 MHz Quarz mit echten 10 MHz (10 MIPs) arbeitet (intern mit 40 MHz).&lt;br /&gt;
&lt;br /&gt;
Der Programmspeicher ist als 8-Bit breit organisiert. Aus dem Grund jeder 16 Bit langer Befehl belegt im Speicher 2 Bytes. Wenn im Datenblatt z.B. 16384 Bytes angegeben sind, bedeutet das, dass dort sich nur die Hälfte davon, also 8192 Befehle abspeichern lassen. Als Folge sind für Befehle nur gerade Adressen zulässig.&lt;br /&gt;
&lt;br /&gt;
== Software ==&lt;br /&gt;
&lt;br /&gt;
Alle Befehle sind um 2 Bit länger, als bei Mid-Range, und es gibt keine Speicherbänke, was Erstellung von Programmen sehr vereinfacht.&lt;br /&gt;
&lt;br /&gt;
Bisher für Mid-Range ausführlich beschriebene Befehle, ausser &amp;quot;CLRW&amp;quot;, &amp;quot;RLF&amp;quot; und &amp;quot;RRF&amp;quot; und Speicherbankumschaltungen (z.B. &amp;quot;BSF RP0&amp;quot; und &amp;quot;BCF RP0&amp;quot;) sind für PIC18F... &amp;quot;verständlich&amp;quot; und werden ausgeführt. Die PIC18F... haben zusätzlich 43 Befehle.&lt;br /&gt;
&lt;br /&gt;
Wenn es um ASM Programm geht, ist er grundsätzlich, ausser zusätzlichen Befehlen, identisch wie bei Mid-Range. Die zusätzliche Befehle ermöglichen Erstellen von mehr kompakten Programmen.&lt;br /&gt;
&lt;br /&gt;
Die PIC18... haben die Möglichkeit für Interuppts individuell Prioritäten definieren, was die Bearbeitung in ISR vereinfacht. Aus dem Grund besitzen sie zwei Interrupt-Vektoren (Anfangsadressen für ISR): 8h für höhere und 18h für niedrigere Prioritäten, die anders als bei übrigen PIC's sind (4h).&lt;br /&gt;
&lt;br /&gt;
Ausser erweiterten Befehlsatz haben die PIC18F... drei Register für indirekte Adressierung FSR0, FSR1 und FSR2, die unabhängig voneinender und gleichzeitig benutzt werden können.&lt;br /&gt;
&lt;br /&gt;
Die CPU's von PIC18F... haben tieferen Stapel für Rücksprungadressen mit 31 Ebenen, der zusätzlich mit &amp;quot;PUSH&amp;quot; und &amp;quot;POP&amp;quot; Befehlen während Ausführung eines Unterprogramms (UP) modifiziert werden kann. Das ermöglichst Änderungen von Rücksprungadressen, so dass nicht unbedingt nach der Ausführung des UP zurück, sondern fast beliebig gesprungen werden kann. Ausführlich ist es in AN818 vom Microchip beschrieben.&lt;br /&gt;
&lt;br /&gt;
Sehr nutzlich sind auch alle neue Sprungmöglichkeiten z.B. &amp;quot;BRA&amp;quot; der &amp;quot;GOTO&amp;quot; entspricht. Da die bedingte Sprünge von Bits des &amp;quot;STATUS&amp;quot; Register abhängen, muß davor kein Befehl aüsgeführt werden der benötigten Bit (z.B. &amp;quot;Z&amp;quot;) prüft.&lt;br /&gt;
&lt;br /&gt;
Wegen Struktur des Programspeichers ein relativer Sprung zur nächster Adresse muss um 2 Byte erfolgen. Deswegen ist für PIC18F... also &amp;quot;GOTO $+2&amp;quot; der kürzeste mögliche Sprung. Bei &amp;quot;GOTO $+1&amp;quot; springt die CPU &amp;quot;zwischen&amp;quot; gültige Befehle ins &amp;quot;Nirvana&amp;quot;, was Absturz des Programms bedeutet. Bei bedingten Sprungen und &amp;quot;BRA&amp;quot; wird der angebebener Wert &amp;quot;n&amp;quot; für die Anzahl den übersprüngten Zeilen automatisch durch 2 multipliziert. &lt;br /&gt;
&lt;br /&gt;
Alle PIC18F... können den Programspeicher beschreiben und sich selbst programmieren. Dafür gibt es die &amp;quot;TBLWT..&amp;quot; Befehle. Das ist aber nur für mindestens 8 Bytes am Stück möglich. Vor dem Beschreiben müssen die dafür vorgesehene Speicherplätze zuerst gelöscht werden, wobei das für minimum 64 Bytes möglich ist.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel ein geprüftes Fragment von Bearbeitung des Programmspeichers (Flash) in http://www.rn-wissen.de/index.php/PIC_ASM_Beispiele.&lt;br /&gt;
&lt;br /&gt;
== Kurzübersicht zusätzliche Befehle ==&lt;br /&gt;
&amp;lt;font style=&amp;quot;font-size:10px;&amp;quot;&amp;gt;&lt;br /&gt;
{| &lt;br /&gt;
|-&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|ADDWFC||Add WREG and Carry bit to f &lt;br /&gt;
|-&lt;br /&gt;
|BC||Branch if Carry&lt;br /&gt;
|-&lt;br /&gt;
|BN||Branch if Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNC||Branch if Not Carry&lt;br /&gt;
|-&lt;br /&gt;
|BNN||Branch if Not Negative&lt;br /&gt;
|-&lt;br /&gt;
|BNOV||Branch if Not Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BNZ||Branch if Not Zero&lt;br /&gt;
|-&lt;br /&gt;
|BOV||Branch if Overflow&lt;br /&gt;
|-&lt;br /&gt;
|BRA||Branch unconditionally&lt;br /&gt;
|-&lt;br /&gt;
|BZ||Branch if Zero&lt;br /&gt;
|-&lt;br /&gt;
|BTG||Bit toggle in f&lt;br /&gt;
|-&lt;br /&gt;
|CPFSEQ||Compare f with W, skip if f=W &lt;br /&gt;
|-&lt;br /&gt;
|CPFSGT||Compare f with W, skip if f&amp;gt;W&lt;br /&gt;
|-&lt;br /&gt;
|CPFSLT||Compare f with W, skip if f&amp;lt;W&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
|-&lt;br /&gt;
|DAW||Decimal Adjust W&lt;br /&gt;
|-&lt;br /&gt;
|DCFSNZ||Decrement f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|INFSNZ||Increment f, skip if not 0&lt;br /&gt;
|-&lt;br /&gt;
|LFSR||Move literal to FSRx&lt;br /&gt;
|-&lt;br /&gt;
|MOVFF||Move f1 to f2&lt;br /&gt;
|-&lt;br /&gt;
|MOVLB||Move literal to BSR &amp;lt; 3 : 0 &amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|MULLW||Multiply literal with W&lt;br /&gt;
|-&lt;br /&gt;
|MULWF||Multiply W with f&lt;br /&gt;
|-&lt;br /&gt;
|NEGF||Negate f&lt;br /&gt;
|-&lt;br /&gt;
|POP||Pop top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|PUSH||Push top of return stack (TOS)&lt;br /&gt;
|-&lt;br /&gt;
|RCALL||Relative call&lt;br /&gt;
|-&lt;br /&gt;
|RESET||Software device RESET&lt;br /&gt;
|-&lt;br /&gt;
|RLCF||Rotate left f through Carry&lt;br /&gt;
|-&lt;br /&gt;
|RLNCF||Rotate left f no Carry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
| valign=top |&lt;br /&gt;
&lt;br /&gt;
{| {{Blauetabelle}}&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
|RRCF||Rotate right f trough Carry&lt;br /&gt;
|-&lt;br /&gt;
|RRNCF||Rotate right f no Carry&lt;br /&gt;
|-&lt;br /&gt;
|SETF||Set f&lt;br /&gt;
|-&lt;br /&gt;
|SUBFWB||Subtract f from W with borrow&lt;br /&gt;
|-&lt;br /&gt;
|SUBWFB||Subtract W from f with borrow&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*||Table Read&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*+||Table Read with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD*-||Table Read with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLRD+*||Table Read with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*||Table write&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*+||Table write with post-increment&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT*-||Table write with post-decrement&lt;br /&gt;
|-&lt;br /&gt;
|TBLWT+*||Table write with pre-increment&lt;br /&gt;
|-&lt;br /&gt;
|TSTFSZ||Test f, skip if 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausführliche Beschreibung zu den Befehlen ==&lt;br /&gt;
&lt;br /&gt;
Alle Sprunge ausser &amp;quot;BRA&amp;quot; können nur im Bereich eines Bytes, d.h. von -128 bis +127 erfolgen. Nur der Sprung &amp;quot;BRA&amp;quot; kann zwischen -1024 bis +1023 lang sein.&lt;br /&gt;
&lt;br /&gt;
Wenn die Bedingung für ein bedingten Sprung nicht erfüllt ist, wird er in einem Takt übersprungen und nächster Befehl ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Erklärungen zu den Verwendeten Platzhaltern:&lt;br /&gt;
*'''k''' stellt einen fest definierten Wert da. z.B. hexadezimal &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;20&amp;lt;/tt&amp;gt;, dezimal  &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;.42&amp;lt;/tt&amp;gt; oder binär &amp;lt;tt&amp;gt;b'00101010'&amp;lt;/tt&amp;gt;&lt;br /&gt;
*'''n''' stellt einen fest definierten Wert wie oben für Sprünge&lt;br /&gt;
*'''W''' steht für das W-Register.&lt;br /&gt;
*'''d''' steht für ''destination'' (Ziel). Im code wird d durch ein &amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; (der Wert wird in das W-Register gespeichert ) oder &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; (der Wert wird in das  davor definierte Register gespeichert)&lt;br /&gt;
*'''b''' steht für Bitnummer im Register (eine Zahl zwischen 0 und 7)&lt;br /&gt;
*'''R''' steht für ein Register&lt;br /&gt;
*'''fett''' geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss&lt;br /&gt;
*&amp;lt;tt&amp;gt;Schreibmaschinenstil&amp;lt;/tt&amp;gt; bedeutet, dass es so im Quellcode geschrieben werden kann.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;ADDWFC R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;ADD W&amp;lt;/b&amp;gt; and &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Addiere W und f mit Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die Rechenoperation &amp;lt;math&amp;gt;W+R&amp;lt;/math&amp;gt; mit Berücksichtigung des schon vorhandenen Übertrags ausgeführt und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNC n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry - Springe wenn kein Übertrag &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;C&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNN n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;egative - Springe wenn nicht negative &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;N&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn kein Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BNZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe wenn ungleich Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gelöschten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BOV n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;OV&amp;lt;/b&amp;gt;erflow - Springe wenn Überlauf &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;OV&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BRA n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;BR&amp;lt;/b&amp;gt;anch &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;bsolutly - Springe unbedingt &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Es wird immer unbedingt gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BZ n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;ranch if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Springe bei Null &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird das &amp;quot;Z&amp;quot; Bit im &amp;quot;STATUS&amp;quot;-Register überprüft und beim gesetzten gesprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;BTG R,b&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;it &amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;o&amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;gle F - Kehre bestimmten Bitwert in f um &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;  &lt;br /&gt;
:Der bestimmte Bit im F-Register wird umgekehrt. Also wenn er vorm Ausführen des Befehls z.B. gleich 1 war, wird er danach gleich 0 sein und umgekehrt.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;b&amp;gt;CPFSEQ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;EQ&amp;lt;/b&amp;gt;ual - Vergleiche Register f mit W und überspringe, wenn f=W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f=W, wird der nächste Befehl übersprungen. Der Zusatz SEQ steht für ''skip if equal'', d.h. wenn die Werte in beiden Register gleich sind, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSGT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;G&amp;lt;/b&amp;gt;rea&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;er - Vergleiche Register f mit W und überspringe, wenn f&amp;gt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;gt;W der nächste Befehl übersprungen. Der Zusatz SGT steht für ''skip if greater'', d.h. wenn der Wert im f grösser als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;CPFSLT R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;om&amp;lt;b&amp;gt;P&amp;lt;/b&amp;gt;are &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with W, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;i&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;tler - Vergleiche Register f mit W und überspringe, wenn f&amp;lt;W&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der Registers f mit dem W verglichen und bei f&amp;lt;W der nächste Befehl übersprungen. Der Zusatz SLT steht für ''skip if littler (lower)'', d.h. wenn der Wert im f kleiner als im W-Register ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DAW&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;ecimal &amp;lt;b&amp;gt;A&amp;lt;/b&amp;gt;djust &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Justiere W-Register nach dezimaler Addition &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es weden alle nötige Korrekturen für richtigen Ergebnis im W-Register nach dezimaler Addition durchgeführt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DCFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;D&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;rement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Subtrahiere 1 vom Regiser f und überspringe den nächsten Befehl, wenn f ungleich Null ist.&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Vom Wert des Registers '''R''' wird 1 subtrahiert und das Ergebnis entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). Weil es keine &amp;quot;echte&amp;quot; Substraktion ist, beeinflusst dieser Befehl das C-Flag im STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;INFSNZ R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;IN&amp;lt;/b&amp;gt;crement &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;, &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;ot &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Addiere 1 zum Register f und überspringe den nächsten Befehl, wenn f ungleich Null ist&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Zum Wert des Registers '''R''' wird 1 addiert und das Ergebniss entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;).  Der Zusatz SNZ steht für ''skip if not zero'', d.h. wenn das Ergebnis der Rechnung ungleich Null ist, wird der nächste Befehl übersprungen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;LFSR R,k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;oad &amp;lt;b&amp;gt;FSR&amp;lt;/b&amp;gt; - Lade FSR-Register mit einem Wert k &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird gewähles FSR-Register (FSR0, FSR1, bzw. FSR2) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVLB k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral to &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;SR &amp;lt;3:0&amp;gt; - Bewege k ins BSR-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt; &lt;br /&gt;
:Es wird der Bank Select Register (BSR) mit dem Wert k geladen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MOVFF R1,R2&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MOV&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;1 to &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt;2 - Bewege f1 in f2&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Das Register R1 wird in das Register R2 kopiert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULLW k&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;iteral with &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;REG - Multipliziere k mit W-Register &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird W-Register mit k multiplieziert und das Ergebnis in Registern PRODH und PRODL gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;MULWF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;MUL&amp;lt;/b&amp;gt;tiply &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Multipliziere W-Register mit F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird F-Register mit W-Register multiplieziert und das Ergebnis in F gespeichert. Dieser Befehl beeinflusst das STATUS-Register nicht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;NEGF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;NEG&amp;lt;/b&amp;gt;ate &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Negiere F&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es werden alle Bits von F-Regiester negiert.  Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;POP&amp;lt;/b&amp;gt; top of return stack (TOS) - Nehme die oberste Rücksprungsadresse vom Stapel weg&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird die oberste Rücksprungadresse vom Stapel entfernt und alle übrigen Adressen um eine Stelle nach oben geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         A   Adresse 1 -----&amp;gt; entfernt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach oben      |   ..........&lt;br /&gt;
   verschieben    |   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1 ---&amp;gt; verworfen&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      Adresse 4&lt;br /&gt;
                      ..........&lt;br /&gt;
                      ?????????&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;PUSH&amp;lt;/b&amp;gt; top of return stack (TOS) - Lege neue oberste Rücksprungsadresse am Stapel &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird eine neue oberste Rücksprungadresse am Stapel abgelegt und alle übrigen Adressen um eine Stelle nach unten geschoben.&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
   alle             &amp;lt;--- Stapel ---&amp;gt;|&lt;br /&gt;
   übrige         |   Adresse 1 &amp;lt;--- neue wird abgelegt&lt;br /&gt;
   Adressen       |   Adresse 2&lt;br /&gt;
   um 1 Stelle    |   Adresse 3&lt;br /&gt;
   nach unten     |   ..........&lt;br /&gt;
   verschieben    V   Adresse 31&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;vor dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      Adresse 3&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 31&lt;br /&gt;
&lt;br /&gt;
                 &amp;lt;--- Stapel ---&amp;gt;|               ;nach dem &amp;quot;POP&amp;quot;&lt;br /&gt;
                      PC + 2&lt;br /&gt;
                      Adresse 1&lt;br /&gt;
                      Adresse 2&lt;br /&gt;
                      ..........&lt;br /&gt;
                      Adresse 30&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RCALL n&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;elative &amp;lt;b&amp;gt;CALL&amp;lt;/b&amp;gt; - Relativer Aufruf eines Unterprogramms &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird ein Unterprogramm reletiv aufgerufen, der innerhalb 1 kB von aktueller Adresse liegen darf. Vergleiche mit &amp;quot;CALL&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt; &amp;lt; Software device &amp;lt;b&amp;gt;RESET&amp;lt;/b&amp;gt; - Software Reset &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird Reset des PIC's durchgeführt, genauso wie hardwaremässig mit /MCLR-Pin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|&amp;lt;-7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
  V                        A&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  c  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  7  6 5 4 3 2 1 0 c ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RLNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;L&amp;lt;/b&amp;gt;eft &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach links&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach links verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7&amp;lt;-6&amp;lt;-5&amp;lt;-4&amp;lt;-3&amp;lt;-2&amp;lt;-1&amp;lt;-0&lt;br /&gt;
      V                    A&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ;0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     6 5 4 3 2 1 0 7 ;nach der Rotation&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight through &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f mithilfe des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Dabei wird das Carry bit (&amp;lt;tt&amp;gt;STATUS,C&amp;lt;/tt&amp;gt;) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register '''R''' wird in das Carry bit &amp;quot;geschoben&amp;quot;. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
 |c|-&amp;gt;7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
  A                        V&lt;br /&gt;
  |________________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
 |C| |-Register  R-| ;C steht für das Carry-bit, STATUS,C ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
  C  7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
  0  C 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;RRNCF R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;otate &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ight &amp;lt;b&amp;gt;N&amp;lt;/b&amp;gt;o &amp;lt;b&amp;gt;C&amp;lt;/b&amp;gt;arry &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; - Rotiere das Register f ohne des Carry-bits nach rechts&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register '''R''' werden um eine Position nach rechts verschoben. Das Ergebnis wird entweder in das W-Register ('''d'''=&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;) oder in R gespeichert ('''d'''=&amp;lt;tt&amp;gt;F&amp;lt;/tt&amp;gt;=&amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;). &lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
      |&amp;lt;--- Register R ---&amp;gt;|&lt;br /&gt;
      7-&amp;gt;6-&amp;gt;5-&amp;gt;4-&amp;gt;3-&amp;gt;2-&amp;gt;1-&amp;gt;0&lt;br /&gt;
      A                    V&lt;br /&gt;
      |____________________|&lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
:Zur Verdeutlichung:&lt;br /&gt;
&amp;lt;dl&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
     |-Register  R-| ; 0-7 stehen für Bitnummer im Register.&lt;br /&gt;
     7 6 5 4 3 2 1 0 ;vor der Rotation&lt;br /&gt;
     0 7 6 5 4 3 2 1 ;nach der Rotation &lt;br /&gt;
&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;!-- zum einrücken da--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SETF R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SETF&amp;lt;/b&amp;gt; - Setze das Register f&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Alle Bits im Register ''R'' werden gesetzt, also nach dem Ausführen des Befehls wird im Register &amp;quot;FFh&amp;quot; stehen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBFWB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das F-Register von W-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des W-Registers wird vom F-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SUBWFB R,d&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;SUB&amp;lt;/b&amp;gt;stract &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt; from &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; with &amp;lt;b&amp;gt;B&amp;lt;/b&amp;gt;orrow - Substrahiere das W-Register von F-Register mit Übertrag&amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Der inhalt des F-Registers wird vom W-Register mit Berücksichtigung des vorhandenes Übertrags abgezogen. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu  [[#Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register|Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*&amp;lt;/b&amp;gt; - Zeiger auf Lesebetabelle ohne Änderung &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*+&amp;lt;/b&amp;gt; with post-increment - Zeiger auf Lesetabelle mit Nacherhöhung &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D*-&amp;lt;/b&amp;gt; with post-decrement - Zeiger auf Lesetabelle mit Nacherniedrigung &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLRD+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;R&amp;lt;/b&amp;gt;ea&amp;lt;b&amp;gt;D+*&amp;lt;/b&amp;gt; with pre-increment - Zeiger auf Lesetabelle mit Vorerhöhung &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Lesen des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*&amp;lt;/b&amp;gt;e - Zeiger auf Schreibetabelle ohne Änderung &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung bleibt der Zeiger unverändert.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*+&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*+&amp;lt;/b&amp;gt;e with post-increment - Zeiger auf Schreibetabelle mit Nacherhöhung &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Diesers Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT*-&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T*-&amp;lt;/b&amp;gt;e with post-decrement - Zeiger auf Schreibetabelle mit Nacherniedrigung &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Nach der Ausführung wird der Zeiger um 1 erniedrigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TBLWT+*&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;a&amp;lt;b&amp;gt;BL&amp;lt;/b&amp;gt;e &amp;lt;b&amp;gt;W&amp;lt;/b&amp;gt;ri&amp;lt;b&amp;gt;T+*&amp;lt;/b&amp;gt;e with pre-increment - Zeiger auf Schreibetabelle mit Vorerhöhung &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Dieser Befehl wird fürs Beschreiben des Programmspeichers (Flash) angewendet. Vor der Ausführung wird der Zeiger um 1 erhöht.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TSTFSZ R&amp;lt;/b&amp;gt; &amp;lt;i style=&amp;quot;color:grey;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;T&amp;lt;/b&amp;gt;e&amp;lt;b&amp;gt;ST&amp;lt;/b&amp;gt;t &amp;lt;b&amp;gt;F&amp;lt;/b&amp;gt; &amp;lt;b&amp;gt;S&amp;lt;/b&amp;gt;kip if &amp;lt;b&amp;gt;Z&amp;lt;/b&amp;gt;ero - Prüfe f, überspringe wenn gleich Null ist &amp;lt;/i&amp;gt;&amp;lt;hr&amp;gt;&lt;br /&gt;
:Es wird der nächste Befehl öbersprungen, wenn der Register f gleich Null ist.&lt;br /&gt;
&lt;br /&gt;
== Umschreiben von Programmen ==&lt;br /&gt;
&lt;br /&gt;
Es werden alle nötige Änderungen beschrieben, die vorhandenes Programm lauffähig machen.&lt;br /&gt;
Ausserdem muß für gewünschten PIC nötige Konfiguration im Quellcode ersetzt werden. Weil einige Befehle von PIC18F... müssen für Mid-Range in UPs umgeschrieben werden, die Auführung Zeit vom umgeschriebenen Program kann sich erheblich ändern. Bei zeitkritischen Abläufen ist deswegen Umschreibung High-End -&amp;gt; Mid-Range nicht immer möglich.&lt;br /&gt;
&lt;br /&gt;
=== Basic-Line &amp;amp; Mid-Range -&amp;gt; High-End ===&lt;br /&gt;
&lt;br /&gt;
Alle Speicherbankumschaltungen müssen mit &amp;quot;;&amp;quot; ausgeblendet bzw. gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
Da die PIC18F... drei &amp;quot;FSR&amp;quot; Register besitzen muss überall &amp;quot;FSR&amp;quot; konsequent anstatt &amp;quot;FSR&amp;quot; nach Wunsch &amp;quot;FSR0&amp;quot;, &amp;quot;FSR1&amp;quot;, bzw. &amp;quot;FSR2&amp;quot; eingeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Die für PICF18... unverständliche Befehle von Mid-Range müssen, wie folgt, ersetzt werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;CLRW&amp;quot; -&amp;gt; &amp;quot;MOVLW 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RLF&amp;quot; -&amp;gt; &amp;quot;RLCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;RRF&amp;quot; -&amp;gt; &amp;quot;RRCF&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Alle Relative Sprunge mussen verdoppelt werden. Beispielweise jeder &amp;quot;GOTO $+4&amp;quot; Befehl muss durch &amp;quot;GOTO $+8&amp;quot; bzw. &amp;quot;BRA $+8&amp;quot; ersetzt werden (Asführungszeit bei Schleifen beachten).&lt;br /&gt;
&lt;br /&gt;
Beim Umschreiben vorhandenen Programen von PIC12... und PIC16... ist für Interrupts ein kompatibilität Modus vorgesehen, die keine definierte Prioritäten für Interrupts benötigt, was folgendemassen in Initialisierung (Init) festgelegt wird:&lt;br /&gt;
&lt;br /&gt;
 		bcf	RCON,IPEN		; disable priority levels on interrupts&lt;br /&gt;
                                                  (compatibility modus)&lt;br /&gt;
&lt;br /&gt;
=== High-End  -&amp;gt; Basic Line &amp;amp; Mid-Range ===&lt;br /&gt;
&lt;br /&gt;
Alle zusätzliche Befehle sind für Mid-Range PIC's unverständlich und müssen als kleine Unterprogramme erstellt werden. Für einige Befehle ist es enfach:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;MOVFF R1, R2&amp;quot; -&amp;gt; &amp;quot;MOVF R1,0&amp;quot;&lt;br /&gt;
                   &amp;quot;MOVWF R2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Es kann auch komplizierter werden, z.B. für &amp;quot;DAW&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
 DecCor		btfsc	_DC		;dezimale Korrektur (ersetzt &amp;quot;DAW&amp;quot; von PIC18FXXX)&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		btfsc	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		sublw	9&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fdca&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0xF0&lt;br /&gt;
 		sublw	0x90&lt;br /&gt;
 		btfss	_C&lt;br /&gt;
 		bsf	_Fcra&lt;br /&gt;
 		return&lt;br /&gt;
&lt;br /&gt;
In dem UP sind &amp;quot;_Fcra&amp;quot; und &amp;quot;_Fdca&amp;quot; im Program definierte Flags. Siehe dazu [[#Hex Dec Wandlung|Hex Dec Wandlung]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern. Sie sind nur auf PIC12... und PIC16... lauffähig und für PIC18... müssen umgeschrieben werden.&lt;br /&gt;
&lt;br /&gt;
Damit sie möglichst wenig Data- und Programmspeicher benötigen, sind alle Zahlen auf dem Display in der hex Darstellung.&lt;br /&gt;
&lt;br /&gt;
Für alle, die es in Dezimalsystem haben wollen, ist ein Taschenrechner mit hex&amp;lt;-&amp;gt;dec Wandlung nötig.&lt;br /&gt;
&lt;br /&gt;
== PIC Miniterminal ==&lt;br /&gt;
&lt;br /&gt;
Das ist eine Schnittstelle, die nur 2 Leitungen zum Anschluss an PIC braucht. Sie ermöglicht das Steuern von diversen LCD Displays mit üblichem Anschluss (&amp;quot;RS&amp;quot;, &amp;quot;Enable&amp;quot; und 8 Databits) und Abfragen von 3 Tasten.&lt;br /&gt;
&lt;br /&gt;
Sie wird mit einem 2x16 Zeichen Matrixdisplay und 3 Tasten für weiter beschriebene Hilfsprogramme verwendet.&lt;br /&gt;
&lt;br /&gt;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?t=13685]]&lt;br /&gt;
&lt;br /&gt;
== PIC RAM Monitor ==&lt;br /&gt;
&lt;br /&gt;
Er wurde entwickelt um 16 Register (0x20 bis 0x2F) im RAM eines PICs auf dem Display von &amp;quot;PIC Miniterminal&amp;quot;, wie skizziert, beobachten zu können:&lt;br /&gt;
&lt;br /&gt;
            Register Adressen (hex)  20 21 22 23 24 25 26 27&lt;br /&gt;
                                    .-----------------------.&lt;br /&gt;
          Zweistelligen Werte (hex) |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    |                       |&lt;br /&gt;
                                    |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                                    '-----------------------'&lt;br /&gt;
                                     28 29 2A 2B 2C 2D 2E 2F&lt;br /&gt;
&lt;br /&gt;
Es können natürlich auch z.B. PORTs beobachtet werden, wenn sie im HP in ausgewähle Register (0x20 bis 0x2F) kopiert werden. Beispielweise so:&lt;br /&gt;
&lt;br /&gt;
                          ..............&lt;br /&gt;
                          movf   PORTA,0    ; PORTA ins W-Register laden&lt;br /&gt;
                          movwf  0x20       ; und ins Register 0x20 kopieren&lt;br /&gt;
                          movf   PORTB,0    ; PORTB ins W-Register laden&lt;br /&gt;
                          movwf  0x21       ; und ins Register 0x21 kopieren&lt;br /&gt;
                          u.s.w.&lt;br /&gt;
                          ..............&lt;br /&gt;
&lt;br /&gt;
Um das Beobachten zu ermöglichen, wenn wegen Fehler das ASM Programm in einer endloser Schleife &amp;quot;hängt&amp;quot;, wurde Interrupt vom Timer0 angewendet. Dieser Timer wurde gewählt, weil er in allen PICs vorhanden ist. Das Programm zeigt die Registerinhalte auf dem Display ca. 1 mal pro Sekunde, wenn der PIC mit einem 4 MHz Quarz oder internem Oszillator arbeitet.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC RAM Monitor&amp;quot; ist kein selbständiges Programm und wird so konzipiert, dass er in jedes ASM Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Er braucht insgesamt 103 Speicherstellen im Programmspeicher, 10 Register im RAM (0x46 bis 0x4F) und 2 I/O Portpins des PICs für den er benutzt wird. Das beobachtete ASM Programm darf, wegen ISR vom &amp;quot;PIC RAM Monitor&amp;quot;, erst ab der Adresse 0x0023 beginnen. Das UP &amp;quot;@&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei freie Portpins, an die PIC Miniterminal angeschlossen wird, als Ausgang definiert und initialisiert werden. Außerdem muss in die Initialisierung &amp;quot;goto @Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor.asm&lt;br /&gt;
 @Tmp	equ	0x4F&lt;br /&gt;
 @Tmp1	equ	0x4E&lt;br /&gt;
 @Tmp2	equ	0x4D&lt;br /&gt;
 @Tmp3	equ	0x4C&lt;br /&gt;
 @Tmp4	equ	0x4B&lt;br /&gt;
 @Int	equ	0x4A&lt;br /&gt;
 @FSR	equ	0x49&lt;br /&gt;
 @SSR	equ	0x48&lt;br /&gt;
 @SWR	equ	0x47&lt;br /&gt;
 @PORT   equ     0x46&lt;br /&gt;
  		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movf	FSR,0		; FSR Register&lt;br /&gt;
 		movwf	@FSR		; sichern&lt;br /&gt;
 		clrf	@PORT		; Portpins Zustände sichern&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@PORT,0&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@PORT,1&lt;br /&gt;
 		btfss	INTCON,T0IF	; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest	; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,4		; prüfen, ob schon 16d. Timer0 interrupt&lt;br /&gt;
 		goto	$+3		; wenn nicht, Anzeigen der Registerinhalte überspringen&lt;br /&gt;
 		clrf	@Int		; Zähler löschen&lt;br /&gt;
 		call	@		; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		bcf	@CK		; Portpins Zustände wiederherstellen&lt;br /&gt;
 		btfsc	@PORT,1&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@PORT,0&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
  		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
                 org     0x03B8          ; diese Adresse kann gleich max.Adresse - 47h sein&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf   @Tmp2&lt;br /&gt;
 	  	movlw   9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
                 bcf     @DT&lt;br /&gt;
  		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE	; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE	; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0		; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7		; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG	; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0	; zurück auf Bank 0 umschalten&lt;br /&gt;
 		movlw	0x38		; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Und hier ein Beispiel für eine Anwendung mit dem Programm &amp;quot;Erstes.asm&amp;quot; für PIC16F84A:&lt;br /&gt;
&lt;br /&gt;
 ;       Erstes.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7  		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define	_T1	PORTB,5 		; Portpins benennen&lt;br /&gt;
 #define	_T2	PORTB,4&lt;br /&gt;
 #define	_L1	PORTB,3&lt;br /&gt;
 #define	_L2	PORTB,2&lt;br /&gt;
 #define	_L3	PORTB,1&lt;br /&gt;
 #define	_L4	PORTB,0&lt;br /&gt;
 P0	equ	0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	equ	0x21&lt;br /&gt;
 P2	equ	0x22&lt;br /&gt;
 		org   0x0000		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	Haupt		 &lt;br /&gt;
 		org	0x0023          ; hier fängt das &amp;quot;Erstes&amp;quot; an&lt;br /&gt;
 Haupt		btfsc	_T1		; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 		goto	T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 T2Test	btfsc	_T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
 		goto	Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
 		bsf	_L4		; schalte _L4 an (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L4		; schalte _L4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L3		; schalte _L3 an (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L3		; schalte _L3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L2		; schalte _L2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L2		; schalte _L2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	_L1		; schalte _L1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
 		call	Warten		; warte&lt;br /&gt;
 		bcf	_L1		; schalte _L1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		goto	Haupt		; springe zu Haupt&lt;br /&gt;
 Warten	movlw	2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
 		movwf	P2		; ins Register P2&lt;br /&gt;
 		clrf	P1		; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
 		clrf	P0		; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
 		decfsz	P0,1		; dekrementiere P0, überspringe nächsten Befehl bei P0 = 0&lt;br /&gt;
 		goto	$-1		; gehe zur vorherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
 		decfsz	P1,1		; dekrementiere P1, überspringe nächsten Befehl bei P1 = 0 &lt;br /&gt;
 		goto	$-4		; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
 		decfsz	P2,1		; dekrementiere P2, überspringe nächsten Befehl bei P2 = 0&lt;br /&gt;
 		goto	$-7             ; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
 		return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init		clrf	PORTB	        ; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
 		bsf	STATUS,RP0	; auf Bank1 umschalten&lt;br /&gt;
 		bcf	OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
 		movlw	0x30		; definiere PortB: Pins 5 und 4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
 		movwf	TRISB		; schreibe in TRIS Register&lt;br /&gt;
  		bcf	STATUS,RP0	; auf Bank0 umschalten&lt;br /&gt;
 		goto	@Init		; * initialisiere &amp;quot;PIC RAM Monitor&amp;quot;	&lt;br /&gt;
 					; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC RAM Monitor.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
 &lt;br /&gt;
Mit dem &amp;quot;*&amp;quot; wurden 3 Zeilen gekenzeichnet, die, in das mit PIC RAM Monitor beobachtetes ASM Programm, eingefügt werden müssen.&lt;br /&gt;
&lt;br /&gt;
Falls im beobachteten ASM Programm Interrupts benutzt werden, muss die ISR um die Prüfungen anderen Interrupt Flags ergänzt werden, was in der ISR als &amp;quot;eigener Code&amp;quot; eingetragen ist. Der PIC RAM Monitor reagiert nur auf Timer0 Interrupt Flag.&lt;br /&gt;
&lt;br /&gt;
Wenn keine I/O Pins mehr frei sind, kann der PIC Miniterminal parallel zur schon vorhandenen Hardware an die als Ausgänge definierte Portpins angeschlossen werden. In dem Fall werden aber die Ausgänge durch Ausgabe auf das Display gestört, was in Kauf genommen werden muss. Die Anschlüsse &amp;quot;@DT&amp;quot; und &amp;quot;@CK&amp;quot; müssen entsprechend definiert werden, z.B beim &amp;quot;Erstes.asm&amp;quot; für den PIC12F629:&lt;br /&gt;
&lt;br /&gt;
 #define 	@DT	_L3		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define 	@CK	_L4		; * für &amp;quot;PIC RAM Monitor&amp;quot;&lt;br /&gt;
 #define 	_T1	GPIO,3          ; Portpins benennen&lt;br /&gt;
 #define 	_T2	GPIO,4&lt;br /&gt;
 #define 	_L1	GPIO,5&lt;br /&gt;
 #define 	_L2	GPIO,2&lt;br /&gt;
 #define 	_L3	GPIO,1&lt;br /&gt;
 #define 	_L4	GPIO,0&lt;br /&gt;
&lt;br /&gt;
Demensprechend wird die Leitung &amp;quot;@DT&amp;quot; an GPIO,1 (Pin 6) und &amp;quot;@CK&amp;quot; an GPIO,0 (Pin 7) angeschlossen.&lt;br /&gt;
&lt;br /&gt;
== PIC Trainer ==&lt;br /&gt;
&lt;br /&gt;
Das ist im Prinzip ein &amp;quot;PIC RAM Monitor&amp;quot;, das um ein paar Funktionen erweitert wurde. Mit diesem Programm wurden schon mehrere ASM Programme erstellt, z.B. [[#Hex Dec Wandlung|Hex Dec Wandlung]].&lt;br /&gt;
&lt;br /&gt;
Auch hier wurde Timer0 Interrupt verwendet, aber die Frequenz beträgt 2 Interrupts pro Sekunde. Das Programm benötigt ein &amp;quot;PIC Miniterminal&amp;quot;, das an 2 freigewählte Portpins des PICs, die sowohl als Ein- als auch Ausgänge funktionieren, angeschlossen wird. Es ist kein selbständiges Programm, das in  jedes Programm, das den Timer0 nicht benutzt, eingebunden werden kann. Es belegt 187 Speicherstellen im Programmspeicher und 11 Register im RAM (0x45 bis 0x4F). Die alle mit &amp;quot;*&amp;quot; gekennzeichnete Zeilen (alle außer &amp;quot;goto @Init&amp;quot; können geändert werden), müssen im Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, enthalten sein. Wegen ISR darf das Programm, in das &amp;quot;PIC Trainer&amp;quot; eingebunden ist, erst ab der Adresse 0x001E anfangen. Das HP &amp;quot;@Trainer&amp;quot;, alle UPs und die Sprungtabelle können für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. Dabei muss auch im UP @Test der Wert im PCLATH geändert werden. Siehe dazu [[#Tabellen|Tabellen]]. &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeiden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an. &lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang zwischen der Register-Adresse und der Nummer des aufgerufenen Programm-Fragments zeigt folgende Skizze:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
                           -----&amp;gt;0  1  2  3  4  5  6  7&amp;lt;-----TestX Nummer, für beiden Nibbles gleich&lt;br /&gt;
                          /     -----------------------&lt;br /&gt;
              Register   2     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
              Adresse    \     |XX XX XX XX XX XX XX XX|&lt;br /&gt;
                          \     -----------------------&lt;br /&gt;
                           -----&amp;gt;8  9  A  B  C  D  E  F&lt;br /&gt;
&lt;br /&gt;
Es wird empfohlen, für schnelle Orientierung, sich die Nummer auf das Display anzubringen. &lt;br /&gt;
&lt;br /&gt;
Funktionen den Tasten:&lt;br /&gt;
&lt;br /&gt;
T1 - bewegt den Cursor auf dem Display um eine Position nach rechts. Am rechten Ende der unteren Zeile springt der Cursor wieder nach ganz links in die obere Zeile.&lt;br /&gt;
&lt;br /&gt;
T2 - erhöht (incrementiert) das Nibble an der Cursor-Position. Nach dem Fh kommt 0, 1, 2, usw.&lt;br /&gt;
&lt;br /&gt;
T3 - startet ein TestX mit der Nummer 0 bis Fh, die gleich dem rechten Nibble der Adresse des Registers an der Cursor-Position ist.&lt;br /&gt;
&lt;br /&gt;
Die Tasten werden 2 mal pro Sekunde während des Interrupts eigelesen und man braucht sie zum gewünschten Ergebniss gedrückt halten und dann los lassen. Gleichzeitiges Drücken mehr als einer Taste ist nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Üben&amp;quot; zu ermöglichen und das Funktionieren des Programms zu Verstehen, wurde ein kurzes Testprogramm geschrieben.&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Trainer&amp;quot; eignet sich besonders gut zum erstellen von ASM Programmen, da beim einmaligen &amp;quot;brennen&amp;quot; des PICs bis zum 16 Programmfragmente die mit &amp;quot;return&amp;quot; enden (z.B. ein HP als UP) nacheinander aufgerufen und mit bilibigen, in Register eingestellten Werten , getestet werden können. &lt;br /&gt;
&lt;br /&gt;
Der Quellcode:&lt;br /&gt;
  &lt;br /&gt;
 ;	PIC Trainer.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @Tasten 	equ	0x45&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,3  		; prüfen, ob schon 8. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Tasten auswerten und Registerinhalte anzeigen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
  		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x80			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		btfsc	@LPC,4&lt;br /&gt;
 		addlw	0x30&lt;br /&gt;
 		addwf	@LPC,0&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x20&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1                 ; @LPC1=@LPC/2&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
                 bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int                    ; Variablen initialisieren (löschen)&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out    		; @DT und @CK als Ausgänge&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 		org	0x3EF                   ; diese Adresse kann gleich max.Adresse - 10h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm:&lt;br /&gt;
&lt;br /&gt;
 ;	Testprogramm.asm&lt;br /&gt;
  	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
  	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
  	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	@DT	PORTB,7 		; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	@CK	PORTB,6 		; * für &amp;quot;PIC Trainer&amp;quot;&lt;br /&gt;
 #define	@TDT	TRISB,7 		; * definiere ensprechende Bits im TRISx Register	&lt;br /&gt;
 #define	@TCK	TRISB,6 		; * für o.g. Anschlüsse&lt;br /&gt;
 		org     0x0000 		; hier fängt das gesamte ASM Programm an	&lt;br /&gt;
 		call	Init		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 		goto	@Trainer		 &lt;br /&gt;
 		org	0x001E          ; ab da kann eigener Code anfangen&lt;br /&gt;
 Test0		incf	0x2F,1&lt;br /&gt;
  		return&lt;br /&gt;
 Test1		incf	0x2E,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test2		incf	0x2D,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test3		incf	0x2C,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test4		incf	0x2B,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test5		incf	0x2A,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test6		incf	0x29,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test7		incf	0x28,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test8		incf	0x27,1&lt;br /&gt;
 		return&lt;br /&gt;
 Test9		incf	0x26,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestA		incf	0x25,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestB		incf	0x24,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestC		incf	0x23,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestD		incf	0x22,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestE		incf	0x21,1&lt;br /&gt;
 		return&lt;br /&gt;
 TestF		incf	0x20,1&lt;br /&gt;
                 goto    TestF&lt;br /&gt;
 Init		;--------------;&lt;br /&gt;
                 ; eigener Code ;&lt;br /&gt;
                 ;--------------;&lt;br /&gt;
                 goto	@Init		; * initialisiere &amp;quot;PIC Trainer&amp;quot;	&lt;br /&gt;
                                         ; hier endet das gesamte ASM Programm&lt;br /&gt;
 		include &amp;quot;PIC Trainer.asm&amp;quot;	 	&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;PIC Trainer&amp;quot; kann auch für grösseres Display (mehr Register und Testx) modifiziert werden. Als Beispiel ein Quellcode für 4x16 Display (0 bis 1Fh Register/Test):&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Trainer32.asm&lt;br /&gt;
 #define 	@Ftst	@Int,7                  ; Variablen definieren (Register benennen)&lt;br /&gt;
 @SWR		equ	0x4F&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @FSR		equ	0x4D&lt;br /&gt;
 @Tmp		equ	0x4C&lt;br /&gt;
 @Tmp1		equ	0x4B&lt;br /&gt;
 @Tmp2		equ	0x4A&lt;br /&gt;
 @Tmp3		equ	0x49&lt;br /&gt;
 @Int		equ	0x48&lt;br /&gt;
 @LPC		equ	0x47&lt;br /&gt;
 @LPC1		equ	0x46&lt;br /&gt;
 @LPC2		equ	0x45&lt;br /&gt;
 @Tasten 	equ	0x44&lt;br /&gt;
 		ORG	0x0004  		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE		; interrupts sperren&lt;br /&gt;
 		movwf	@SWR			; W-Register sichern&lt;br /&gt;
 		swapf	STATUS,0		; STATUS Register&lt;br /&gt;
 		movwf	@SSR			; sichern&lt;br /&gt;
 		movf	FSR,0			; FSR Register&lt;br /&gt;
 		movwf	@FSR			; sichern&lt;br /&gt;
 		btfss	INTCON,T0IF		; Timer0 interrupt Flag prüfen&lt;br /&gt;
 		goto	@IntTest		; wenn nicht gesetzt, eventuell andere prüfen&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		incf	@Int,1  		; Zähler erhöhen&lt;br /&gt;
 		btfss	@Int,2  		; prüfen, ob schon 4. Timer0 interrupt&lt;br /&gt;
 		goto	$+3			; wenn nicht, zum &amp;quot;@IntTest&amp;quot; springen&lt;br /&gt;
 		clrf	@Int			; Zähler löschen&lt;br /&gt;
 		call	@			; Anzeigen der Registerinhalte aufrufen&lt;br /&gt;
 @IntTest 	;**************;&lt;br /&gt;
 		; eigener Code ;&lt;br /&gt;
 		;**************;&lt;br /&gt;
 		movf	@FSR,0  		; FSR Register&lt;br /&gt;
 		movwf	FSR			; wiederherstellen&lt;br /&gt;
 		swapf	@SSR,0  		; STATUS Register&lt;br /&gt;
 		movwf	STATUS  		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0  		; W-Register wiederherstellen&lt;br /&gt;
 		retfie  			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x0358                  ; diese Adresse kann gleich max.Adresse - A7h sein&lt;br /&gt;
 @Trainer 	btfss	@Ftst&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		bcf	@Ftst&lt;br /&gt;
 		call	@Test&lt;br /&gt;
 		call	@Zeigen&lt;br /&gt;
 		goto	@Trainer&lt;br /&gt;
 		ORG     0x0338&lt;br /&gt;
 @ 		bsf	STATUS,RP0		; @DT und @CK als Eingänge&lt;br /&gt;
 		bsf	@TDT&lt;br /&gt;
 		bsf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		clrf	@Tasten 		; Zustände von @DT und @CK ins @Tasten kopieren&lt;br /&gt;
 		btfsc	@CK&lt;br /&gt;
 		bsf	@Tasten,0&lt;br /&gt;
 		btfsc	@DT&lt;br /&gt;
 		bsf	@Tasten,1&lt;br /&gt;
 		movf	@Tasten,1		; Tasten auswerten &lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		bsf	@Ftst			; setze Flag, wenn Taste3 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@IncLPC 		; nächstes Nibble, wenn T2 gedrückt&lt;br /&gt;
 		movf	@Tasten,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		call	@Inc			; nibble erhöhen, wenn T1 gedrückt&lt;br /&gt;
 @Zeigen 	call	@Out&lt;br /&gt;
 		movlw	0x20			; Anzeigen der Registerinhalte&lt;br /&gt;
 		movwf	FSR		&lt;br /&gt;
 		movlw	0x0C			; Cursor aus&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		call	@1st&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@2nd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@3rd&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		call	@4th&lt;br /&gt;
 		call	@Line&lt;br /&gt;
 		movlw	0x0E			; Cursor an&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		swapf	@LPC,0			; Display Adresse berechnen und Cursor plazieren&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		movwf	@LPC2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x80&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	1&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x30&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	2&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		goto	$+3&lt;br /&gt;
 		movlw	0x70&lt;br /&gt;
 		goto	@AddLPC&lt;br /&gt;
 		movf	@LPC2,0&lt;br /&gt;
 		sublw	3&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		movlw	0xA0&lt;br /&gt;
 @AddLPC 	addwf	@LPC,0			&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
 @Out		bsf	STATUS,RP0		; @DT und @CK als Ausgänge&lt;br /&gt;
 		bcf	@TDT&lt;br /&gt;
 		bcf	@TCK&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		return&lt;br /&gt;
 @Test		movlw	3			; Test0-1F starten&lt;br /&gt;
 		movwf	PCLATH&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		andlw	0x1F&lt;br /&gt;
 		goto	@TestTab&lt;br /&gt;
 @Inc		movlw	0x20			; Register Wert erhöhen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		movf	@LPC1,0&lt;br /&gt;
 		addwf	FSR,1&lt;br /&gt;
 		btfsc	@LPC,0	&lt;br /&gt;
 		goto	@IncLN&lt;br /&gt;
 @IncHN  	movlw	0x10			; High Nibble erhöhen&lt;br /&gt;
 		addwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLN          incf	INDF,1  		; Low Nibble erhöhen&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		andlw	0x0F&lt;br /&gt;
 		btfss	STATUS,Z&lt;br /&gt;
 		return&lt;br /&gt;
 		movlw	0x10&lt;br /&gt;
 		subwf	INDF,1&lt;br /&gt;
 		return&lt;br /&gt;
 @IncLPC         incf	@LPC,1  		; Zähler der Position in der Zeile erhöhen&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		sublw	0x40&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		movf	@LPC,0&lt;br /&gt;
 		movwf	@LPC1&lt;br /&gt;
 		rrf	@LPC1,1&lt;br /&gt;
 		return&lt;br /&gt;
 @Line		movlw	8			; Zeile an Display schicken&lt;br /&gt;
 		movwf	@Tmp&lt;br /&gt;
 		movf	INDF,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		decfsz	@Tmp,1&lt;br /&gt;
 		goto	$-4&lt;br /&gt;
 		return&lt;br /&gt;
 @1st		movlw	0x80			; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0			; Adresse der 2. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @3rd		movlw	0x90			; Adresse der 3. Zeile an Display schicken&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @4th		movlw	0xD0			; Adresse der 4. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C		; Befehl an Display schicken&lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1			; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F			; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2		&lt;br /&gt;
 		movlw	0x0A&lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send		movwf	@Tmp2&lt;br /&gt;
 	  	movlw	9			; Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT			; setze Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@CK			; lösche&lt;br /&gt;
 		bcf	@DT			; Display&lt;br /&gt;
 		bsf	@DT			; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return&lt;br /&gt;
 @Init		bsf	INTCON,GIE		; alle interrupts erlauben&lt;br /&gt;
 		bsf	INTCON,T0IE		; Timer0 interrupt erlauben&lt;br /&gt;
 		bcf	INTCON,T0IF		; Timer0 interrupt Flag löschen&lt;br /&gt;
 		bsf	STATUS,RP0		; auf Bank 1 umschalten&lt;br /&gt;
 		movf	OPTION_REG,0    	; OPTION_REG in W-Register laden&lt;br /&gt;
 		andlw	0xC0			; Timer0 konfigurieren&lt;br /&gt;
 		iorlw	7			; Prescaler 256:1 &lt;br /&gt;
 		movwf	OPTION_REG		; ins OPTION_REG schreiben&lt;br /&gt;
 		bcf	STATUS,RP0		; zurück auf Bank 0 umschalten&lt;br /&gt;
 		clrf	@Int&lt;br /&gt;
 		clrf	@LPC&lt;br /&gt;
 		clrf	@LPC1&lt;br /&gt;
 		call	@Out&lt;br /&gt;
 		movlw	0x38			; Display vom PIC Miniterminal initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		return&lt;br /&gt;
  		org	0x3DF                   ; diese Adresse kann gleich max.Adresse - 20h sein&lt;br /&gt;
 @TestTab 	addwf	PCL,1			; Sprungtabelle&lt;br /&gt;
 		goto	Test0&lt;br /&gt;
 		goto	Test1&lt;br /&gt;
 		goto	Test2&lt;br /&gt;
 		goto	Test3&lt;br /&gt;
 		goto	Test4&lt;br /&gt;
 		goto	Test5&lt;br /&gt;
 		goto	Test6&lt;br /&gt;
 		goto	Test7&lt;br /&gt;
 		goto	Test8&lt;br /&gt;
 		goto	Test9&lt;br /&gt;
 		goto	TestA&lt;br /&gt;
 		goto	TestB&lt;br /&gt;
 		goto	TestC&lt;br /&gt;
 		goto	TestD&lt;br /&gt;
 		goto	TestE&lt;br /&gt;
 		goto	TestF&lt;br /&gt;
 		goto	Test10&lt;br /&gt;
 		goto	Test11&lt;br /&gt;
 		goto	Test12&lt;br /&gt;
 		goto	Test13&lt;br /&gt;
 		goto	Test14&lt;br /&gt;
 		goto	Test15&lt;br /&gt;
 		goto	Test16&lt;br /&gt;
 		goto	Test17&lt;br /&gt;
 		goto	Test18&lt;br /&gt;
 		goto	Test19&lt;br /&gt;
 		goto	Test1A&lt;br /&gt;
                goto	Test1B&lt;br /&gt;
       		goto	Test1C&lt;br /&gt;
 		goto	Test1D&lt;br /&gt;
 		goto	Test1E&lt;br /&gt;
                goto	Test1F&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Es können eigene Namen für mit &amp;quot;PIC Trainer&amp;quot; erstellten und geprüften UPs vewendet werden. Sie müssen nur im eigenem Programm mit &amp;quot;#define&amp;quot; den entsprechenden TestX zugewiesen werden. Aus unerklärlichen Gründen funktioniert es aber nur, wenn die Definitionen als erste im Quelcode sind (MPASM Falle?).&lt;br /&gt;
&lt;br /&gt;
 #define	Test0		Init&lt;br /&gt;
 #define	Test1		Lesen&lt;br /&gt;
 #define	Test2		Schreiben&lt;br /&gt;
                  usw.&lt;br /&gt;
&lt;br /&gt;
Somit wird z.B. das UP &amp;quot;Lesen&amp;quot; aufgerufen wenn die Taste T3 gedrückt wird und der Cursor auf der Register-Adresse &amp;quot;21&amp;quot; steht. Es wird empfohlen, eine Tabelle mit UPs-Namen und den enstprechenden Nummern (0 bis Fh) zum dessen Aufrufen, sich zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Für alle definierte, aber noch nicht existierende UPs, sollten &amp;quot;return&amp;quot; Befehle angewendet werden, um einen Programmabsturtz durch versehentliches Aufrufen von dennen, zu vermeinden. Zum Beispiel:&lt;br /&gt;
&lt;br /&gt;
 #define	TestD	RAMClr&lt;br /&gt;
 #define	TestE	RAMSet&lt;br /&gt;
 #define	TestF	KeyTst&lt;br /&gt;
&lt;br /&gt;
 RAMClr		return&lt;br /&gt;
 RAMSet		return&lt;br /&gt;
 KeyTst		return&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP (z.B. eine Warteschleife) läuft, kann ein nächstes erst nach seiner Beendigung gestartet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ein UP in einer endloser Schleife &amp;quot;hängen&amp;quot; bleibt, dann kann nur anderes UP nicht gestartet werden. Die alle andere Funktionen des Programms werden nicht gestört. In dem Testprogramm wurde absichtlich TestF als endlose Schleife erstellt, um das Funktionieren des &amp;quot;PIC Trainer&amp;quot;s in diesem Fall zu zeigen.&lt;br /&gt;
&lt;br /&gt;
== PIC Profiler ==&lt;br /&gt;
&lt;br /&gt;
Der &amp;quot;PIC Profiler&amp;quot; ermöglicht das Messen von Ausführungszeit eines ASM UPs, also Programm-Fragments das mit &amp;quot;return&amp;quot; endet. Es wird die gesamte Ausführungszeit gemessen mit &amp;quot;call&amp;quot; (2 Takten) und &amp;quot;return&amp;quot; (2 Takten) inklusive. Um ein HP messen zu können, muss es ins UP umgewandelt werden, wie im [[#Unterprogramm|Unterprogramm]] erklärt. &lt;br /&gt;
&lt;br /&gt;
Zum Messen wurde Timer0 benutzt, der um 2 Byte Zähler erweitert wurde. Somit beträgt die maximale messbare Ausführungszeit  FFFFFFFFh = 4 294 967 295 Prozessortakten, was mehr als einer Stunde beim 4 MHz Quarz entspricht. Bis FFFFh ist das Messergebniss genau, weiter wurde es nicht getestet.   &lt;br /&gt;
&lt;br /&gt;
Um die Durchführung der Messung zu ermöglichen, wird das &amp;quot;goto Haupt&amp;quot; für den MPASM mit einem Semikolon augeblendet und &amp;quot;goto @Profiler&amp;quot; eingeschrieben. Nach dem Einschalten wird anstatt ins &amp;quot;Haupt&amp;quot; zum &amp;quot;@Profiler&amp;quot; gesprungen. Der &amp;quot;@Profiler&amp;quot; misst die Ausführungszeit nur einmal, da er mit &amp;quot;sleep&amp;quot; endet. Wenn endlose Messung gewünscht wird, muss der Befehl &amp;quot;sleep&amp;quot; mit &amp;quot;goto @Profiler&amp;quot; ersetzt werden. Wegen ISR vom &amp;quot;PIC Profiler&amp;quot; darf das Programm, in dem gemessen wird, erst ab der Adresse 0x0013 anfangen.&lt;br /&gt;
 &lt;br /&gt;
Zum Darstellen des Messergebnisses kann entweder schon im zu messenden Programm vorhandenes Display bzw. &amp;quot;PIC Miniterminal&amp;quot; benutzt werden. Das hex Ergebniss befindet sich in den Register @A3 (MSB), @A2, @A1 und @A0 (LSB).&lt;br /&gt;
&lt;br /&gt;
Die Version, die das im Programm vorhandenes Display benutzt, braucht 46 Speicherstellen im Programmspeicher und 8 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler1.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		movf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		movf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03E0          ; diese Adresse kann gleich max.Adresse - 1Fh sein&lt;br /&gt;
 @Profiler	clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf   @A1		; @A1 kopieren&lt;br /&gt;
 		movwf   @RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	Ausgeben	; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
                                         ; auf einem Display anzeigen (eigener Code)&lt;br /&gt;
 		sleep&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
Die Version, die zur Ausgabe den &amp;quot;PIC Miniterminal&amp;quot; benutzt, belegt 94 Speicherstellen im Programmspeicher und 12 Register im RAM.&lt;br /&gt;
&lt;br /&gt;
 ;	PIC Profiler2.asm&lt;br /&gt;
 @SWR		equ	0x4F            ; Variablen deklarieren (Register benennen)&lt;br /&gt;
 @SSR		equ	0x4E&lt;br /&gt;
 @A3		equ	0x4D&lt;br /&gt;
 @A2		equ	0x4C&lt;br /&gt;
 @A1		equ	0x4B&lt;br /&gt;
 @A0		equ	0x4A&lt;br /&gt;
 @ATmp		equ	0x49&lt;br /&gt;
 @RTmp		equ	0x48&lt;br /&gt;
 @Tmp            equ     0x47		; * Variablen für &amp;quot;PIC Miniterminal&amp;quot; definieren&lt;br /&gt;
 @Tmp1	        equ     0x46&lt;br /&gt;
 @Tmp2	        equ     0x45&lt;br /&gt;
 @Tmp3	        equ     0x44	&lt;br /&gt;
 		ORG	0x0004		; ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&lt;br /&gt;
 		bcf	INTCON,T0IF	; Timer0 interrupt flag löschen&lt;br /&gt;
 		movwf	@SWR		; W-Register sichern&lt;br /&gt;
 		movf	STATUS,0	; STATUS Register&lt;br /&gt;
 		movwf	@SSR		; sichern&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	@A2,1		; erhöhe @A2, wenn Timer0 überlaufen ist&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		incf	@A3,1		; erhöhe @A3, wenn @A2 überlaufen ist&lt;br /&gt;
 		movf	@SSR,0		; STATUS Register&lt;br /&gt;
 		movwf	STATUS		; wiederherstellen&lt;br /&gt;
 		movf	@SWR,0		; W-Register wiederherstellen&lt;br /&gt;
 		clrf	TMR0		; Timer0 und Prescaler löschen&lt;br /&gt;
 		retfie			; zurück ins gemessene UP, Interrupts erlauben&lt;br /&gt;
 		org	0x03B0          ; diese Adresse kann gleich max.Adresse - 4Fh sein&lt;br /&gt;
 @Profiler	movlw   0x38		; Display vom &amp;quot;PIC Miniterminal&amp;quot; initialisieren&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	0x0C&lt;br /&gt;
 		call	@Cmd&lt;br /&gt;
 		movlw	6&lt;br /&gt;
 		call	@Cmd &lt;br /&gt;
 	        clrf	@A3             ; Messregister löschen&lt;br /&gt;
 		clrf	@A2&lt;br /&gt;
 		bsf	STATUS,RP0	; Bank1&lt;br /&gt;
 		movlw	0xC7		; interner Takt&lt;br /&gt;
 		movwf	OPTION_REG	; Timer0 konfigurieren&lt;br /&gt;
 		bcf	STATUS,RP0	; Bank 0&lt;br /&gt;
 		movlw	0xE0		; nur Timer0 Interrupt erlaubt&lt;br /&gt;
 		movwf	INTCON		; Interrupts konfigurieren&lt;br /&gt;
 		clrf	TMR0		; Timer0 löschen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		call	Messen		; dieses UP wird gemessen&lt;br /&gt;
 ;............................................................................&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0CS	; &amp;quot;stopp&amp;quot; Timer0&lt;br /&gt;
 		bcf	STATUS,RP0	&lt;br /&gt;
 		movf	TMR0,0		; TMR0 ins Register&lt;br /&gt;
 		movwf	@A1		; @A1 kopieren&lt;br /&gt;
 		movwf	@RTmp&lt;br /&gt;
 		clrf	@ATmp		; Prescaler ins Register @A0 kopieren&lt;br /&gt;
 		incf	@ATmp,1&lt;br /&gt;
 		bsf	STATUS,RP0&lt;br /&gt;
 		bsf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	OPTION_REG,T0SE&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		movf	TMR0,0&lt;br /&gt;
 		subwf	@RTmp,0&lt;br /&gt;
 		btfsc	STATUS,Z&lt;br /&gt;
 		goto	$-8&lt;br /&gt;
 		comf	@ATmp,1&lt;br /&gt;
 		incf	@ATmp,0&lt;br /&gt;
 		movwf	@A0&lt;br /&gt;
 		decf	@A0,1&lt;br /&gt;
 		call	@1st		; Messergebniss aus @A3, @A2, @A1 und @A0&lt;br /&gt;
 					; auf &amp;quot;PIC Miniterminal&amp;quot; ausgeben&lt;br /&gt;
 		movf	@A3,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A2,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A1,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		movf	@A0,0&lt;br /&gt;
 		call	@Val&lt;br /&gt;
 		sleep&lt;br /&gt;
 @1st		movlw	0x80		; Adresse der 1. Zeile an Display schicken&lt;br /&gt;
 @Cmd		bcf	STATUS,C	; Befehl an Display schicken &lt;br /&gt;
 		goto	@Send&lt;br /&gt;
 @Val		movwf	@Tmp1		; Zahl (00-FF) an Display schicken&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 @Num		andlw	0x0F		; Ziffer (0-F) an Display schicken&lt;br /&gt;
 		movwf	@Tmp2 &lt;br /&gt;
 		movlw	0x0A &lt;br /&gt;
 		subwf	@Tmp2,0&lt;br /&gt;
 		btfsc	STATUS,C&lt;br /&gt;
 		addlw	7&lt;br /&gt;
 		addlw	0x3A&lt;br /&gt;
 		bsf	STATUS,C&lt;br /&gt;
 @Send          	movwf	@Tmp2&lt;br /&gt;
 		movlw	9		; ein Byte + RS aus @Tmp2 (9 Bits) an Display schicken&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 @Ser 		bcf	@CK&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		btfsc	@Tmp2,7&lt;br /&gt;
 		bsf	@DT&lt;br /&gt;
 		bsf	@CK&lt;br /&gt;
 		rlf	@Tmp2,1&lt;br /&gt;
 		decfsz  @Tmp3,1&lt;br /&gt;
 		goto	@Ser&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		bcf	@DT&lt;br /&gt;
 		return &lt;br /&gt;
 		end &lt;br /&gt;
&lt;br /&gt;
Das Programm &amp;quot;@Profiler&amp;quot; kann für PICs, die mehr Programmspeicher besitzen, mit entsprechender &amp;quot;org&amp;quot; Direktive höher verschoben werden. &lt;br /&gt;
&lt;br /&gt;
Als praktisches Beispiel wurde das UP &amp;quot;Warten&amp;quot; vom &amp;quot;Erstes.asm&amp;quot; für den PIC16F84A gemessen und das Ergebniss auf dem &amp;quot;PIC Miniterminal&amp;quot; dargestellt.&lt;br /&gt;
&lt;br /&gt;
 ;     Erstesp.asm&lt;br /&gt;
 	list      P=16F84A		; Prozessor definieren&lt;br /&gt;
 	include &amp;quot;P16F84A.inc&amp;quot;		; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&lt;br /&gt;
 #define	    Messen  Warten	        ; definiere das zu messende UP&lt;br /&gt;
 #define	    @DT	  PORTB,7	        ; * definiere Anschlüsse @DT und @CK&lt;br /&gt;
 #define	    @CK	  PORTB,6	        ; * für &amp;quot;PIC Miniterminal&amp;quot;&lt;br /&gt;
 #define	    _T1	  PORTB,5	        ; Portpins benennen&lt;br /&gt;
 #define	    _T2	  PORTB,4&lt;br /&gt;
 #define	    _L1	  PORTB,3&lt;br /&gt;
 #define	    _L2	  PORTB,2&lt;br /&gt;
 #define	    _L3	  PORTB,1&lt;br /&gt;
 #define	    _L4	  PORTB,0&lt;br /&gt;
 P0         equ   0x20			; Variablen definieren (Register benennen)&lt;br /&gt;
 P1	   equ   0x21&lt;br /&gt;
 P2	   equ   0x22&lt;br /&gt;
 	   org   0x0000 		; hier fängt das ASM Programm in dem gemessen wird an	&lt;br /&gt;
 	   call    Init 		; rufe UP Init (Initialisierung) auf&lt;br /&gt;
 	   ;goto    Haupt		 &lt;br /&gt;
 	   goto    @Profiler	&lt;br /&gt;
 	   org     0x0013               ; hier fängt das Program, in dem gemessen wird, an&lt;br /&gt;
 Haupt	   btfsc   _T1			; prüfe, ob Taster T1 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto T2Test&amp;quot;&lt;br /&gt;
 	   goto    T2Test		; wenn nicht, springe zu T2Test&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte ca. 0,4 s (400 000 Prozessortakten)&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
 T2Test     btfsc   _T2			; prüfe, ob Taster T2 gedrückt ist, wenn ja,&lt;br /&gt;
 					; überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
            goto    Haupt		; Wenn nicht, springe zu Haupt&lt;br /&gt;
            bsf     _L4			; schalte _L4 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L4			; schalte _L4 aus&lt;br /&gt;
            bsf     _L3			; schalte _L3 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L3			; schalte _L3 aus&lt;br /&gt;
            bsf     _L2			; schalte _L2 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L2			; schalte _L2 aus&lt;br /&gt;
            bsf     _L1			; schalte _L1 an&lt;br /&gt;
            call    Warten		; warte&lt;br /&gt;
            bcf     _L1			; schalte _L1 aus&lt;br /&gt;
            goto    Haupt		; springe zu Haupt&lt;br /&gt;
 Warten     movlw   2			; schreibe &amp;quot;2&amp;quot; für ca. 0,4 s&lt;br /&gt;
            movwf   P2			; ins Register P2&lt;br /&gt;
            clrf    P1			; lösche Register P1 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe) &lt;br /&gt;
            clrf    P0			; lösche Register P0 (schreibe &amp;quot;0&amp;quot; für 256 Durchläufe)&lt;br /&gt;
            decfsz  P0,1        	        ; dekrementiere P0, überspringe nächsten Befehl bei P0=0&lt;br /&gt;
            goto    $-1			; gehe zur voherigen Adresse (Befehl &amp;quot;decfsz  P0&amp;quot;) &lt;br /&gt;
            decfsz  P1,1        	        ; dekrementiere P1, überspringe nächsten Befehl bei P1=0 &lt;br /&gt;
            goto    $-4			; gehe zur aktueller Adresse - 4 (Befehl &amp;quot;clrf P0&amp;quot;)&lt;br /&gt;
            decfsz  P2,1        	        ; dekrementiere P2, überspringe nächsten Befehl bei P2=0&lt;br /&gt;
            goto    $-7			; gehe zur aktueller Adresse - 7 (Befehl &amp;quot;clrf P1&amp;quot;)&lt;br /&gt;
            return			; springe zurück zum Aufrufer (&amp;quot;Haupt&amp;quot;),&lt;br /&gt;
 Init	   clrf    PORTB		; lösche Port (setze alle werdende Ausgänge auf &amp;quot;0&amp;quot;)&lt;br /&gt;
    	   bsf	    STATUS,RP0		; auf Bank1 umschalten&lt;br /&gt;
   	   bcf	    OPTION_REG,7	; aktiviere pull-ups&lt;br /&gt;
      	   movlw   0x30 		; definiere PortB: Pins B5 und B4 als Eingänge&lt;br /&gt;
 					; und die restlichen als Ausgänge (00110000b) &lt;br /&gt;
  	   movwf  TRISB 		; schreibe in TRIS Register&lt;br /&gt;
  	   bcf    STATUS,RP0		; auf Bank0 umschalten&lt;br /&gt;
            return&lt;br /&gt;
       					; hier endet das ASM Programm in dem gemessen wird&lt;br /&gt;
  	   include &amp;quot;PIC Profiler2.asm&amp;quot;	 	&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>PICture</name></author>	</entry>

	</feed>